diff options
author | Alexandre Oliva <aoliva@redhat.com> | 2007-10-02 01:42:09 +0000 |
---|---|---|
committer | Alexandre Oliva <aoliva@redhat.com> | 2007-10-02 01:42:09 +0000 |
commit | 18709e5e8a145296bac1ce2c07aa088e0b164018 (patch) | |
tree | a94bb5163f7b6e2ed2b09860cad2197ecbdd703b | |
parent | 9614cb30a621f20cb46bfc637d86a98f7b8830d3 (diff) |
* tree-inline.c (processing_debug_stmt_p): New variable.
(remap_decl): Register variables only while not processing debug
statements.
(copy_body_r): Enqueue debug statements for later processing.
(copy_bb): Skip debug statements.
(copy_edges_for_bb): Likewise.
(copy_debug_stmt): New fn.
(copy_debug_stmts): New fn.
(copy_generic_body, copy_body): Call it.
(setup_one_parameter): Insert debug notes for inlined parms.
(estimated_num_insns_1): Handle debug stmts.
(optimize_inline_calls): Initialize debug stmt queue.
(tree_function_versioning): Likewise.
* tree-into-ssa.c (mark_def_sites): Handle debug stmts.
(var_debug_value_for_decl): New fn.
(adjust_debug_stmts_for_var_def_move): New fn.
(adjust_debug_stmts_for_move): New fn.
(check_debug_predicate): New struct.
(check_and_update_debug_stmt_1): New fn.
(check_and_update_debug_stmt): New fn.
(insert_phi_nodes_for): Introduce debug stmts for phi nodes.
(rewrite_stmt): Likewise, for SSA defs.
(mark_use_interesting): Handle debug stmts.
(prepare_block_for_update): Likewise.
* tree.c (build_var_debug_value_stat): New fn.
(empty_body_p): Handle debug stmts.
* tree.def (VAR_DEBUG_VALUE): New tree code.
* tree.h (VAR_DEBUG_VALUE_SET_VAR): New macro.
(VAR_DEBUG_VALUE_VAR): Likewise.
(VAR_DEBUG_VALUE_VALUE): Likewise.
(IS_DEBUG_STMT): Likewise.
(MAY_HAVE_DEBUG_STMTS): Likewise.
(VAR_DEBUG_VALUE_NOVALUE): Likewise.
(build_var_debug_value_stat): Declare.
(build_var_debug_value): New macro.
(var_debug_value_for_decl): Declare.
* tree-gimple.c (is_gimple_stmt): Handle debug stmts.
* tree-ssa-operands.c (opf_debug_use): New flag.
(get_expr_operands): Handle debug stmts. Don't mark objects
addressed in debug stmts as addressable.
(parse_ssa_operands): Handle debug stmts.
* tree-dump.c (dequeue_and_dump): Likewise.
* tree-pretty-print.c (dump_generic_node): Likewise.
* tree-ssa-dce (mark_stmt_if_obviously_necessary): Likewise.
(necessary_p): New function.
(eliminate_unnecessary_stmts): Handle debug stmts.
* tree-ssa-propagate.c (get_rhs): Likewise.
* tree-ssa.c (verify_ssa): Likewise.
(execute_early_warn_uninitialized): Likewise.
* tree-ssa-live.c (remove_unused_locals): Likewise.
(set_var_live_on_entry): Likewise.
* tree-ssa-dom.c (propagate_rhs_into_lhs): Likewise.
* tree-flow-inline.h (has_zero_uses): Ignore uses in debug stmts.
(has_single_use): Likewise.
(single_imm_use): Likewise.
(num_imm_uses): Likewise.
(bsi_next_nondebug): New fn.
(bsi_prev_nondebug): Likewise.
(bsi_start_nondebug): Likewise.
(bsi_last_nondebug): Likewise.
* tree-ssa-phiopt.c (empty_block_p): Ignore debug stmts.
* tree-ssa-sink.c (all_immediate_uses_same_place): Likewise.
(nearest_common_dominator_of_uses): Check for debug stmts.
(statement_sink_location): Handle debug stmts.
* tree-ssa-threadedge.c
(record_temporary_equivalences_from_stmts): Skip debug stmts.
* tree-ssa-threadupdate.c (redirection_block_p): Ignore them.
* tree-cfgcleanup.c (tree_forwarder_block_p): Likewise.
* tree-outof-ssa.c (replace_use_variable): Don't clear.
(analyze_edges_for_bb): Handle debug stmts.
* tree-cfg.c (first_stmt): Skip debug stmts.
(last_stmt): Likewise.
(last_and_only_stmt): Likewise.
(verify_expr): Verify debug value.
(tree_block_ends_with_call_p): Skip debug stmts.
* tree-flow.h (bsi_next_nondebug): Declare.
(bsi_prev_nondebug): Likewise.
(bsi_start_nondebug): Likewise.
(bsi_last_nondebug): Likewise.
(adjust_debug_stmts_for_move): Likewise.
(adjust_debug_stmts_for_var_def_move): Likewise.
(check_and_update_debug_stmt): Likewise.
* tree-ssa-reassoc.c (linearize_expr): Adjust debug stmts.
(linearize_expr_tree): Likewise.
* tree-ssa-loop-ch.c (should_duplicate_loop_header_p): Skip debug
stmts.
* tree-ssa-ter.c (find_replaceable_in_bb): Likewise.
* tree-ssa-loop-ivopts.c (find_interesting_uses_stmt): Likewise.
(remove_unused_ivs): Adjust debug stmts.
* tree-ssa-loop-im.c (rewrite_bittest): Likewise.
(move_computations_stmt): Likewise.
* tree-ssanames.c (release_ssa_name): Likewise.
* tree-ssa-alias.c (find_used_portions): Handle debug exprs.
* tree-ssa-structalias.c (compute_points_to_sets): Ignore debug
stmts.
* tree-tailcall.c (find_tail_calls): Handle debug stmts.
* tree-vrp.c (find_assert_locations): Likewise.
* tree-ssa-coalesce.c (build_ssa_conflict_graph): Likewise.
(create_outofssa_var_map): Likewise.
* tree-ssa-forwprop.c (forward_propagate_addr_expr): Handle debug
stmts.
* tree-ssa-pre.c (compute_avail): Skip debug stmts.
* tree-ssa-loop-manip.c (find_uses_to_rename_stmt): Likewise.
(check_loop_closed_ssa_stmt): Likewise.
* tree-inline.h (copy_body_data): Add debug_stmts queue.
* ipa-pure-const.c (scan_function): Skip debug stmts.
* ipa-reference.c (scan_for_static_refs): Likewise.
* ipa-type-escape.c (scan_for_refs): Likewise.
* tree-stdarg.c (execute_optimize_stdarg): Likewise.
git-svn-id: https://gcc.gnu.org/svn/gcc/branches/var-tracking-assignments-branch@128945 138bc75d-0d04-0410-961f-82ee72b054a4
43 files changed, 822 insertions, 52 deletions
diff --git a/gcc/ChangeLog.vta b/gcc/ChangeLog.vta index 0386826678f..69679b2a06a 100644 --- a/gcc/ChangeLog.vta +++ b/gcc/ChangeLog.vta @@ -1,5 +1,117 @@ 2007-10-01 Alexandre Oliva <aoliva@redhat.com> + * tree-inline.c (processing_debug_stmt_p): New variable. + (remap_decl): Register variables only while not processing debug + statements. + (copy_body_r): Enqueue debug statements for later processing. + (copy_bb): Skip debug statements. + (copy_edges_for_bb): Likewise. + (copy_debug_stmt): New fn. + (copy_debug_stmts): New fn. + (copy_generic_body, copy_body): Call it. + (setup_one_parameter): Insert debug notes for inlined parms. + (estimated_num_insns_1): Handle debug stmts. + (optimize_inline_calls): Initialize debug stmt queue. + (tree_function_versioning): Likewise. + * tree-into-ssa.c (mark_def_sites): Handle debug stmts. + (var_debug_value_for_decl): New fn. + (adjust_debug_stmts_for_var_def_move): New fn. + (adjust_debug_stmts_for_move): New fn. + (check_debug_predicate): New struct. + (check_and_update_debug_stmt_1): New fn. + (check_and_update_debug_stmt): New fn. + (insert_phi_nodes_for): Introduce debug stmts for phi nodes. + (rewrite_stmt): Likewise, for SSA defs. + (mark_use_interesting): Handle debug stmts. + (prepare_block_for_update): Likewise. + * tree.c (build_var_debug_value_stat): New fn. + (empty_body_p): Handle debug stmts. + * tree.def (VAR_DEBUG_VALUE): New tree code. + * tree.h (VAR_DEBUG_VALUE_SET_VAR): New macro. + (VAR_DEBUG_VALUE_VAR): Likewise. + (VAR_DEBUG_VALUE_VALUE): Likewise. + (IS_DEBUG_STMT): Likewise. + (MAY_HAVE_DEBUG_STMTS): Likewise. + (VAR_DEBUG_VALUE_NOVALUE): Likewise. + (build_var_debug_value_stat): Declare. + (build_var_debug_value): New macro. + (var_debug_value_for_decl): Declare. + * tree-gimple.c (is_gimple_stmt): Handle debug stmts. + * tree-ssa-operands.c (opf_debug_use): New flag. + (get_expr_operands): Handle debug stmts. Don't mark objects + addressed in debug stmts as addressable. + (parse_ssa_operands): Handle debug stmts. + * tree-dump.c (dequeue_and_dump): Likewise. + * tree-pretty-print.c (dump_generic_node): Likewise. + * tree-ssa-dce (mark_stmt_if_obviously_necessary): Likewise. + (necessary_p): New function. + (eliminate_unnecessary_stmts): Handle debug stmts. + * tree-ssa-propagate.c (get_rhs): Likewise. + * tree-ssa.c (verify_ssa): Likewise. + (execute_early_warn_uninitialized): Likewise. + * tree-ssa-live.c (remove_unused_locals): Likewise. + (set_var_live_on_entry): Likewise. + * tree-ssa-dom.c (propagate_rhs_into_lhs): Likewise. + * tree-flow-inline.h (has_zero_uses): Ignore uses in debug stmts. + (has_single_use): Likewise. + (single_imm_use): Likewise. + (num_imm_uses): Likewise. + (bsi_next_nondebug): New fn. + (bsi_prev_nondebug): Likewise. + (bsi_start_nondebug): Likewise. + (bsi_last_nondebug): Likewise. + * tree-ssa-phiopt.c (empty_block_p): Ignore debug stmts. + * tree-ssa-sink.c (all_immediate_uses_same_place): Likewise. + (nearest_common_dominator_of_uses): Check for debug stmts. + (statement_sink_location): Handle debug stmts. + * tree-ssa-threadedge.c + (record_temporary_equivalences_from_stmts): Skip debug stmts. + * tree-ssa-threadupdate.c (redirection_block_p): Ignore them. + * tree-cfgcleanup.c (tree_forwarder_block_p): Likewise. + * tree-outof-ssa.c (replace_use_variable): Don't clear. + (analyze_edges_for_bb): Handle debug stmts. + * tree-cfg.c (first_stmt): Skip debug stmts. + (last_stmt): Likewise. + (last_and_only_stmt): Likewise. + (verify_expr): Verify debug value. + (tree_block_ends_with_call_p): Skip debug stmts. + * tree-flow.h (bsi_next_nondebug): Declare. + (bsi_prev_nondebug): Likewise. + (bsi_start_nondebug): Likewise. + (bsi_last_nondebug): Likewise. + (adjust_debug_stmts_for_move): Likewise. + (adjust_debug_stmts_for_var_def_move): Likewise. + (check_and_update_debug_stmt): Likewise. + * tree-ssa-reassoc.c (linearize_expr): Adjust debug stmts. + (linearize_expr_tree): Likewise. + * tree-ssa-loop-ch.c (should_duplicate_loop_header_p): Skip debug + stmts. + * tree-ssa-ter.c (find_replaceable_in_bb): Likewise. + * tree-ssa-loop-ivopts.c (find_interesting_uses_stmt): Likewise. + (remove_unused_ivs): Adjust debug stmts. + * tree-ssa-loop-im.c (rewrite_bittest): Likewise. + (move_computations_stmt): Likewise. + * tree-ssanames.c (release_ssa_name): Likewise. + * tree-ssa-alias.c (find_used_portions): Handle debug exprs. + * tree-ssa-structalias.c (compute_points_to_sets): Ignore debug + stmts. + * tree-tailcall.c (find_tail_calls): Handle debug stmts. + * tree-vrp.c (find_assert_locations): Likewise. + * tree-ssa-coalesce.c (build_ssa_conflict_graph): Likewise. + (create_outofssa_var_map): Likewise. + * tree-ssa-forwprop.c (forward_propagate_addr_expr): Handle debug + stmts. + * tree-ssa-pre.c (compute_avail): Skip debug stmts. + * tree-ssa-loop-manip.c (find_uses_to_rename_stmt): Likewise. + (check_loop_closed_ssa_stmt): Likewise. + * tree-inline.h (copy_body_data): Add debug_stmts queue. + * ipa-pure-const.c (scan_function): Skip debug stmts. + * ipa-reference.c (scan_for_static_refs): Likewise. + * ipa-type-escape.c (scan_for_refs): Likewise. + * tree-stdarg.c (execute_optimize_stdarg): Likewise. + +2007-10-01 Alexandre Oliva <aoliva@redhat.com> + * common.opt (fvar-tracking-assignments): New. * doc/invoke.texi: Document it. * toplev.c (flag_var_tracking_assignments): New. diff --git a/gcc/ipa-pure-const.c b/gcc/ipa-pure-const.c index 519b402df20..ab8545da046 100644 --- a/gcc/ipa-pure-const.c +++ b/gcc/ipa-pure-const.c @@ -467,6 +467,10 @@ scan_function (tree *tp, } break; + case VAR_DEBUG_VALUE: + *walk_subtrees = 0; + break; + case ADDR_EXPR: /* This case is here to find addresses on rhs of constructors in decl_initial of static variables. */ diff --git a/gcc/ipa-reference.c b/gcc/ipa-reference.c index 1a962c52cdb..9002edf0000 100644 --- a/gcc/ipa-reference.c +++ b/gcc/ipa-reference.c @@ -552,6 +552,10 @@ scan_for_static_refs (tree *tp, } break; + case VAR_DEBUG_VALUE: + *walk_subtrees = 0; + break; + case ADDR_EXPR: /* This case is here to find addresses on rhs of constructors in decl_initial of static variables. */ diff --git a/gcc/ipa-type-escape.c b/gcc/ipa-type-escape.c index 5303e79ec26..bf11f0b0499 100644 --- a/gcc/ipa-type-escape.c +++ b/gcc/ipa-type-escape.c @@ -1612,6 +1612,10 @@ scan_for_refs (tree *tp, int *walk_subtrees, void *data) } break; + case VAR_DEBUG_VALUE: + *walk_subtrees = 0; + break; + case ADDR_EXPR: /* This case is here to find addresses on rhs of constructors in decl_initial of static variables. */ diff --git a/gcc/tree-cfg.c b/gcc/tree-cfg.c index c15e81e20b4..40ec164073f 100644 --- a/gcc/tree-cfg.c +++ b/gcc/tree-cfg.c @@ -2591,7 +2591,13 @@ tree first_stmt (basic_block bb) { block_stmt_iterator i = bsi_start (bb); - return !bsi_end_p (i) ? bsi_stmt (i) : NULL_TREE; + tree stmt = NULL; + while (!bsi_end_p (i) && IS_DEBUG_STMT ((stmt = bsi_stmt (i)))) + { + bsi_next (&i); + stmt = NULL; + } + return stmt; } /* Return the last statement in basic block BB. */ @@ -2600,7 +2606,14 @@ tree last_stmt (basic_block bb) { block_stmt_iterator b = bsi_last (bb); - return !bsi_end_p (b) ? bsi_stmt (b) : NULL_TREE; + tree stmt = NULL; + + while (!bsi_end_p (b) && IS_DEBUG_STMT ((stmt = bsi_stmt (b)))) + { + bsi_prev (&b); + stmt = NULL; + } + return stmt; } /* Return the last statement of an otherwise empty block. Return NULL @@ -2610,14 +2623,15 @@ last_stmt (basic_block bb) tree last_and_only_stmt (basic_block bb) { - block_stmt_iterator i = bsi_last (bb); + block_stmt_iterator i = bsi_last_nondebug (bb); tree last, prev; if (bsi_end_p (i)) return NULL_TREE; last = bsi_stmt (i); - bsi_prev (&i); + bsi_prev_nondebug (&i); + if (bsi_end_p (i)) return last; @@ -3151,6 +3165,15 @@ verify_expr (tree *tp, int *walk_subtrees, void *data ATTRIBUTE_UNUSED) } break; + case VAR_DEBUG_VALUE: + check_and_update_debug_stmt (t, NULL); + /* Walking sub-trees could fail to verify ADDR_EXPRs referencing + variables that became non-addressable due to optimization, + and perhaps other reasons as well. We could perform some + more limited form of checking. */ + *walk_subtrees = 0; + break; + case ADDR_EXPR: { bool old_invariant; @@ -6249,7 +6272,7 @@ debug_loop_ir (void) static bool tree_block_ends_with_call_p (basic_block bb) { - block_stmt_iterator bsi = bsi_last (bb); + block_stmt_iterator bsi = bsi_last_nondebug (bb); return get_call_expr_in (bsi_stmt (bsi)) != NULL; } diff --git a/gcc/tree-cfgcleanup.c b/gcc/tree-cfgcleanup.c index bcae4488dc1..69548fee276 100644 --- a/gcc/tree-cfgcleanup.c +++ b/gcc/tree-cfgcleanup.c @@ -270,6 +270,11 @@ tree_forwarder_block_p (basic_block bb, bool phi_wanted) return false; break; + /* ??? For now, hope there's a corresponding debug + assignment at the destination. */ + case VAR_DEBUG_VALUE: + break; + default: return false; } diff --git a/gcc/tree-dump.c b/gcc/tree-dump.c index 6821e363bb3..66da6dd53b4 100644 --- a/gcc/tree-dump.c +++ b/gcc/tree-dump.c @@ -605,6 +605,11 @@ dequeue_and_dump (dump_info_p di) dump_child ("op 1", GIMPLE_STMT_OPERAND (t, 1)); break; + case VAR_DEBUG_VALUE: + dump_child ("op 0", VAR_DEBUG_VALUE_VAR (t)); + dump_child ("op 1", VAR_DEBUG_VALUE_VALUE (t)); + break; + case COMPONENT_REF: dump_child ("op 0", TREE_OPERAND (t, 0)); dump_child ("op 1", TREE_OPERAND (t, 1)); diff --git a/gcc/tree-flow-inline.h b/gcc/tree-flow-inline.h index 71e607bddce..0c13992eddb 100644 --- a/gcc/tree-flow-inline.h +++ b/gcc/tree-flow-inline.h @@ -524,18 +524,48 @@ next_readonly_imm_use (imm_use_iterator *imm) static inline bool has_zero_uses (const_tree var) { - const ssa_use_operand_t *const ptr = &(SSA_NAME_IMM_USE_NODE (var)); + const ssa_use_operand_t *ptr, *start; + bool ret; + + ptr = &(SSA_NAME_IMM_USE_NODE (var)); /* A single use means there is no items in the list. */ - return (ptr == ptr->next); + ret = (ptr == ptr->next); + + if (ret || !MAY_HAVE_DEBUG_STMTS) + return ret; + + start = ptr; + for (ptr = start->next; ptr != start; ptr = ptr->next) + if (!IS_DEBUG_STMT (ptr->stmt)) + return false; + return true; } /* Return true if VAR has a single use. */ static inline bool has_single_use (const_tree var) { - const ssa_use_operand_t *const ptr = &(SSA_NAME_IMM_USE_NODE (var)); + const ssa_use_operand_t *ptr, *start; + bool ret; + + ptr = &(SSA_NAME_IMM_USE_NODE (var)); /* A single use means there is one item in the list. */ - return (ptr != ptr->next && ptr == ptr->next->next); + ret = (ptr != ptr->next && ptr == ptr->next->next); + + if (ret) + return !IS_DEBUG_STMT (ptr->next->stmt); + else if (!MAY_HAVE_DEBUG_STMTS) + return ret; + + start = ptr; + for (ptr = start->next; ptr != start; ptr = ptr->next) + if (!IS_DEBUG_STMT (ptr->stmt)) + { + if (ret) + return false; + ret = true; + } + return ret; } @@ -544,8 +574,35 @@ has_single_use (const_tree var) static inline bool single_imm_use (const_tree var, use_operand_p *use_p, tree *stmt) { - const ssa_use_operand_t *const ptr = &(SSA_NAME_IMM_USE_NODE (var)); - if (ptr != ptr->next && ptr == ptr->next->next) + const ssa_use_operand_t *ptr; + bool ret; + + ptr = &(SSA_NAME_IMM_USE_NODE (var)); + + ret = ptr != ptr->next && ptr == ptr->next->next; + + if (ret) + ret = !IS_DEBUG_STMT (ptr->next->stmt); + else if (MAY_HAVE_DEBUG_STMTS) + { + const ssa_use_operand_t *start = ptr, *prev = ptr, *single_use_prev = 0; + + for (ptr = start->next; ptr != start; prev = ptr, ptr = ptr->next) + if (!IS_DEBUG_STMT (ptr->stmt)) + { + if (ret) + { + ret = false; + break; + } + ret = true; + single_use_prev = prev; + } + + ptr = single_use_prev; + } + + if (ret) { *use_p = ptr->next; *stmt = ptr->next->stmt; @@ -564,8 +621,13 @@ num_imm_uses (const_tree var) const ssa_use_operand_t *ptr; unsigned int num = 0; - for (ptr = start->next; ptr != start; ptr = ptr->next) - num++; + if (!MAY_HAVE_DEBUG_STMTS) + for (ptr = start->next; ptr != start; ptr = ptr->next) + num++; + else + for (ptr = start->next; ptr != start; ptr = ptr->next) + if (!IS_DEBUG_STMT (ptr->stmt)) + num++; return num; } @@ -817,6 +879,48 @@ bsi_stmt_ptr (block_stmt_iterator i) return tsi_stmt_ptr (i.tsi); } +/* Modify block statement iterator I so that it is at the next + statement in the basic block. */ +static inline void +bsi_next_nondebug (block_stmt_iterator *i) +{ + do + bsi_next (i); + while (!bsi_end_p (*i) && IS_DEBUG_STMT (bsi_stmt (*i))); +} + +/* Modify block statement iterator I so that it is at the previous + non-debug statement in the basic block. */ +static inline void +bsi_prev_nondebug (block_stmt_iterator *i) +{ + do + bsi_prev (i); + while (!bsi_end_p (*i) && IS_DEBUG_STMT (bsi_stmt (*i))); +} + +static inline block_stmt_iterator +bsi_start_nondebug (basic_block bb) +{ + block_stmt_iterator bsi = bsi_start (bb); + + while (!bsi_end_p (bsi) && IS_DEBUG_STMT (bsi_stmt (bsi))) + bsi_next (&bsi); + + return bsi; +} + +static inline block_stmt_iterator +bsi_last_nondebug (basic_block bb) +{ + block_stmt_iterator bsi = bsi_last (bb); + + while (!bsi_end_p (bsi) && IS_DEBUG_STMT (bsi_stmt (bsi))) + bsi_prev (&bsi); + + return bsi; +} + /* Returns the loop of the statement STMT. */ static inline struct loop * diff --git a/gcc/tree-flow.h b/gcc/tree-flow.h index 518e4f2236e..0ad8ee3a785 100644 --- a/gcc/tree-flow.h +++ b/gcc/tree-flow.h @@ -633,6 +633,10 @@ static inline void bsi_next (block_stmt_iterator *); static inline void bsi_prev (block_stmt_iterator *); static inline tree bsi_stmt (block_stmt_iterator); static inline tree * bsi_stmt_ptr (block_stmt_iterator); +static inline void bsi_next_nondebug (block_stmt_iterator *); +static inline void bsi_prev_nondebug (block_stmt_iterator *); +static inline block_stmt_iterator bsi_start_nondebug (basic_block); +static inline block_stmt_iterator bsi_last_nondebug (basic_block); extern void bsi_remove (block_stmt_iterator *, bool); extern void bsi_move_before (block_stmt_iterator *, block_stmt_iterator *); @@ -890,6 +894,11 @@ void mark_sym_for_renaming (tree); void mark_set_for_renaming (bitmap); tree get_current_def (tree); void set_current_def (tree, tree); +void adjust_debug_stmts_for_move (tree, basic_block, + const block_stmt_iterator *); +void adjust_debug_stmts_for_var_def_move (tree, basic_block, + const block_stmt_iterator *); +void check_and_update_debug_stmt (tree, bool (*)(tree)); /* In tree-ssa-ccp.c */ bool fold_stmt (tree *); diff --git a/gcc/tree-gimple.c b/gcc/tree-gimple.c index 8e976e201fe..fc77c0a89da 100644 --- a/gcc/tree-gimple.c +++ b/gcc/tree-gimple.c @@ -245,6 +245,7 @@ is_gimple_stmt (tree t) case CALL_EXPR: case GIMPLE_MODIFY_STMT: + case VAR_DEBUG_VALUE: /* These are valid regardless of their type. */ return true; diff --git a/gcc/tree-inline.c b/gcc/tree-inline.c index 936808fa875..a0b7b8cae95 100644 --- a/gcc/tree-inline.c +++ b/gcc/tree-inline.c @@ -201,6 +201,8 @@ remap_ssa_name (tree name, copy_body_data *id) return new; } +bool processing_debug_stmt_p = false; + /* Remap DECL during the copying of the BLOCK tree for the function. */ tree @@ -262,7 +264,8 @@ remap_decl (tree decl, copy_body_data *id) if (TREE_CODE (map) == SSA_NAME) set_default_def (t, map); } - add_referenced_var (t); + if (!processing_debug_stmt_p) + add_referenced_var (t); } return t; } @@ -699,6 +702,13 @@ copy_body_r (tree *tp, int *walk_subtrees, void *data) return NULL; } } + else if (IS_DEBUG_STMT (*tp)) + { + *tp = copy_node (*tp); + VARRAY_PUSH_TREE (id->debug_stmts, *tp); + *walk_subtrees = 0; + goto shallow_stmt_copy; + } /* Here is the "usual case". Copy this tree node, and then tweak some special cases. */ @@ -714,6 +724,7 @@ copy_body_r (tree *tp, int *walk_subtrees, void *data) of function call. */ if (EXPR_P (*tp) || GIMPLE_STMT_P (*tp)) { + shallow_stmt_copy: new_block = id->block; if (TREE_BLOCK (*tp)) { @@ -817,6 +828,13 @@ copy_bb (copy_body_data *id, basic_block bb, int frequency_scale, int count_scal { tree *stmtp = bsi_stmt_ptr (copy_bsi); tree stmt = *stmtp; + + if (IS_DEBUG_STMT (stmt)) + { + bsi_next (©_bsi); + continue; + } + call = get_call_expr_in (stmt); if (call && CALL_EXPR_VA_ARG_PACK (call) && id->call_expr) @@ -1102,9 +1120,12 @@ copy_edges_for_bb (basic_block bb, int count_scale, basic_block ret_bb) bool can_throw, nonlocal_goto; copy_stmt = bsi_stmt (bsi); - update_stmt (copy_stmt); - if (gimple_in_ssa_p (cfun)) - mark_symbols_for_renaming (copy_stmt); + if (!IS_DEBUG_STMT (copy_stmt)) + { + update_stmt (copy_stmt); + if (gimple_in_ssa_p (cfun)) + mark_symbols_for_renaming (copy_stmt); + } /* Do this before the possible split_block. */ bsi_next (&bsi); @@ -1337,6 +1358,40 @@ copy_cfg_body (copy_body_data * id, gcov_type count, int frequency, return new_fndecl; } +static void +copy_debug_stmt (tree stmt, copy_body_data *id) +{ + tree t; + + processing_debug_stmt_p = true; + + t = VAR_DEBUG_VALUE_VAR (stmt); + walk_tree (&t, copy_body_r, id, NULL); + VAR_DEBUG_VALUE_SET_VAR (stmt, t); + + walk_tree (&VAR_DEBUG_VALUE_VALUE (stmt), copy_body_r, id, NULL); + + processing_debug_stmt_p = false; + + update_stmt (stmt); + if (gimple_in_ssa_p (cfun)) + mark_symbols_for_renaming (stmt); +} + +static void +copy_debug_stmts (copy_body_data *id) +{ + size_t i, e; + + if (!id->debug_stmts) + return; + + for (i = 0, e = VARRAY_ACTIVE_SIZE (id->debug_stmts); i < e; i++) + copy_debug_stmt (VARRAY_TREE (id->debug_stmts, i), id); + + VARRAY_POP_ALL (id->debug_stmts); +} + /* Make a copy of the body of FN so that it can be inserted inline in another function. */ @@ -1348,6 +1403,7 @@ copy_generic_body (copy_body_data *id) body = DECL_SAVED_TREE (fndecl); walk_tree (&body, copy_body_r, id, NULL); + copy_debug_stmts (id); return body; } @@ -1362,6 +1418,7 @@ copy_body (copy_body_data *id, gcov_type count, int frequency, /* If this body has a CFG, walk CFG and copy. */ gcc_assert (ENTRY_BLOCK_PTR_FOR_FUNCTION (DECL_STRUCT_FUNCTION (fndecl))); body = copy_cfg_body (id, count, frequency, entry_block_map, exit_block_map); + copy_debug_stmts (id); return body; } @@ -1486,8 +1543,18 @@ setup_one_parameter (copy_body_data *id, tree p, tree value, if (init_stmt) bsi_insert_after (&bsi, init_stmt, BSI_NEW_STMT); if (gimple_in_ssa_p (cfun)) - for (;!bsi_end_p (bsi); bsi_next (&bsi)) - mark_symbols_for_renaming (bsi_stmt (bsi)); + { + if (MAY_HAVE_DEBUG_STMTS && var_debug_value_for_decl (var)) + { + tree note = build_var_debug_value (var, + is_gimple_reg (p) + ? def : var); + bsi_insert_after (&bsi, note, BSI_SAME_STMT); + } + + for (;!bsi_end_p (bsi); bsi_next (&bsi)) + mark_symbols_for_renaming (bsi_stmt (bsi)); + } } } @@ -2093,8 +2160,9 @@ estimate_num_insns_1 (tree *tp, int *walk_subtrees, void *data) *walk_subtrees = 0; return NULL; - /* CHANGE_DYNAMIC_TYPE_EXPR explicitly expands to nothing. */ + /* These explicitly expand to nothing. */ case CHANGE_DYNAMIC_TYPE_EXPR: + case VAR_DEBUG_VALUE: *walk_subtrees = 0; return NULL; @@ -2804,6 +2872,8 @@ optimize_inline_calls (tree fn) id.transform_return_to_modify = true; id.transform_lang_insert_block = false; id.statements_to_fold = pointer_set_create (); + if (MAY_HAVE_DEBUG_STMTS) + VARRAY_TREE_INIT (id.debug_stmts, 8, "debug_stmt"); push_gimplify_context (); @@ -3376,6 +3446,9 @@ tree_function_versioning (tree old_decl, tree new_decl, varray_type tree_map, SET_DECL_RTL (new_decl, NULL_RTX); id.statements_to_fold = pointer_set_create (); } + + if (MAY_HAVE_DEBUG_STMTS) + VARRAY_TREE_INIT (id.debug_stmts, 8, "debug_stmt"); id.decl_map = pointer_map_create (); id.src_fn = old_decl; diff --git a/gcc/tree-inline.h b/gcc/tree-inline.h index 895a0afcbbd..d2ac460c572 100644 --- a/gcc/tree-inline.h +++ b/gcc/tree-inline.h @@ -94,6 +94,9 @@ typedef struct copy_body_data /* Statements that might be possibly folded. */ struct pointer_set_t *statements_to_fold; + + /* Debug statements that need processing. */ + varray_type debug_stmts; } copy_body_data; /* Weights of constructions for estimate_num_insns. */ diff --git a/gcc/tree-into-ssa.c b/gcc/tree-into-ssa.c index 2baf879627e..7353a0fd80d 100644 --- a/gcc/tree-into-ssa.c +++ b/gcc/tree-into-ssa.c @@ -742,6 +742,9 @@ mark_def_sites (struct dom_walk_data *walk_data, basic_block bb, REGISTER_DEFS_IN_THIS_STMT (stmt) = 0; REWRITE_THIS_STMT (stmt) = 0; + if (IS_DEBUG_STMT (stmt)) + return; + /* If a variable is used before being set, then the variable is live across a block boundary, so mark it live-on-entry to BB. */ FOR_EACH_SSA_USE_OPERAND (use_p, stmt, iter, SSA_OP_USE) @@ -1104,6 +1107,183 @@ mark_phi_for_rewrite (basic_block bb, tree phi) VEC_replace (tree_vec, phis_to_rewrite, idx, phis); } +/* Decide whether to emit a VAR_DEBUG_VALUE annotation for VAR. */ + +bool +var_debug_value_for_decl (tree var) +{ + if (TREE_CODE (var) != VAR_DECL + && TREE_CODE (var) != PARM_DECL) + return false; + + if (DECL_IGNORED_P (var)) + return false; + + if (!MAY_HAVE_DEBUG_STMTS) + return false; + + if (!is_gimple_reg (var)) + return false; + + return true; +} + +/* Given a VAR whose definition STMT is 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, and + adjust them as needed. If TOBB is NULL, then the definition is + understood as being removed, and TOBSIP is unused. */ +void +adjust_debug_stmts_for_var_def_move (tree var, + basic_block tobb, + const block_stmt_iterator *tobsip) +{ + imm_use_iterator imm_iter; + tree stmt; + use_operand_p use_p; + + if (!MAY_HAVE_DEBUG_STMTS) + return; + + FOR_EACH_IMM_USE_STMT (stmt, imm_iter, var) + { + basic_block bb; + block_stmt_iterator si; + + if (!IS_DEBUG_STMT (stmt)) + continue; + + if (tobb) + { + bb = bb_for_stmt (stmt); + + if (bb != tobb) + { + if (dominated_by_p (CDI_DOMINATORS, bb, tobb)) + continue; + } + else + { + si = *tobsip; + + if (bsi_end_p (si)) + continue; + + do + { + bsi_prev (&si); + if (bsi_end_p (si)) + break; + } + while (bsi_stmt (si) != stmt); + + if (bsi_end_p (si)) + continue; + } + } + + FOR_EACH_IMM_USE_ON_STMT (use_p, imm_iter) + SET_USE (use_p, unshare_expr (SSA_NAME_VALUE (var))); + + 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. */ + +void +adjust_debug_stmts_for_move (tree def, basic_block tobb, + const block_stmt_iterator *tobsip) +{ + 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_ALL_DEFS) + { + tree var = DEF_FROM_PTR (def_p); + + if (TREE_CODE (var) != SSA_NAME) + continue; + + adjust_debug_stmts_for_var_def_move (var, tobb, tobsip); + } +} + +/* Wrapper struct for the function predicate passed to + check_and_update_debug_stmt_1 (). */ + +struct check_debug_predicate +{ + bool (*available_p)(tree); +}; + +/* Look for an SSA_NAME in the expression *TP whose definition was + removed, or is about to be removed, per the available_p predicate + given by the check_debug_predicate *DATA. */ + +static tree +check_and_update_debug_stmt_1 (tree *tp, int *walk_subtrees, + void *data) +{ + tree t = *tp; + + if (EXPR_P (t)) + return NULL_TREE; + + *walk_subtrees = 0; + + if (TREE_CODE (t) == SSA_NAME) + { + struct check_debug_predicate *p = (struct check_debug_predicate *)data; + + if (SSA_NAME_IN_FREE_LIST (t)) + return t; + + if (!SSA_NAME_DEF_STMT (t)) + return t; + + if (IS_EMPTY_STMT (SSA_NAME_DEF_STMT (t)) + && TREE_CODE (SSA_NAME_VAR (t)) != PARM_DECL) + return t; + + if (p->available_p && !p->available_p (t)) + return t; + } + + return NULL_TREE; +} + +/* Look for any SSA_NAMEs in the VALUE of a VAR_DEBUG_VALUE statement + T that have become or are about to become unavailable. + AVAILABLE_P, if non-NULL, is used to determine whether the variable + is about to become unavailable. */ + +void +check_and_update_debug_stmt (tree t, bool (*available_p)(tree)) +{ + struct check_debug_predicate p; + + gcc_assert (IS_DEBUG_STMT (t)); + + if (VAR_DEBUG_VALUE_VALUE (t) == VAR_DEBUG_VALUE_NOVALUE) + return; + + p.available_p = available_p; + if (walk_tree (&VAR_DEBUG_VALUE_VALUE (t), check_and_update_debug_stmt_1, + &p, NULL)) + { + /* ??? Can we do better? */ + VAR_DEBUG_VALUE_VALUE (t) = VAR_DEBUG_VALUE_NOVALUE; + update_stmt (t); + } +} /* Insert PHI nodes for variable VAR using the iterated dominance frontier given in PHI_INSERTION_POINTS. If UPDATE_P is true, this @@ -1173,6 +1353,12 @@ insert_phi_nodes_for (tree var, bitmap phi_insertion_points, bool update_p) { tree sym = DECL_P (var) ? var : SSA_NAME_VAR (var); phi = create_phi_node (sym, bb); + if (!update_p && var_debug_value_for_decl (sym)) + { + tree note = build_var_debug_value (sym, PHI_RESULT (phi)); + block_stmt_iterator si = bsi_after_labels (bb); + bsi_insert_before (&si, note, BSI_SAME_STMT); + } } /* Mark this PHI node as interesting for update_ssa. */ @@ -1378,9 +1564,14 @@ rewrite_stmt (struct dom_walk_data *walk_data ATTRIBUTE_UNUSED, if (REGISTER_DEFS_IN_THIS_STMT (stmt)) FOR_EACH_SSA_DEF_OPERAND (def_p, stmt, iter, SSA_OP_DEF) { - tree var = DEF_FROM_PTR (def_p); + tree var = DEF_FROM_PTR (def_p), name; gcc_assert (DECL_P (var)); - SET_DEF (def_p, make_ssa_name (var, stmt)); + SET_DEF (def_p, name = make_ssa_name (var, stmt)); + if (var_debug_value_for_decl (var)) + { + tree note = build_var_debug_value (var, name); + bsi_insert_after (&si, note, BSI_SAME_STMT); + } register_new_def (DEF_FROM_PTR (def_p), var); } } @@ -2363,7 +2554,12 @@ mark_use_interesting (tree var, tree stmt, basic_block bb, bool insert_phi_p) if (TREE_CODE (stmt) == PHI_NODE) mark_phi_for_rewrite (def_bb, stmt); else - REWRITE_THIS_STMT (stmt) = 1; + { + REWRITE_THIS_STMT (stmt) = 1; + + if (IS_DEBUG_STMT (stmt)) + return; + } /* If VAR has not been defined in BB, then it is live-on-entry to BB. Note that we cannot just use the block holding VAR's @@ -2440,6 +2636,9 @@ prepare_block_for_update (basic_block bb, bool insert_phi_p) stmt = bsi_stmt (si); + if (IS_DEBUG_STMT (stmt)) + continue; + FOR_EACH_SSA_USE_OPERAND (use_p, stmt, i, SSA_OP_ALL_USES) { tree use = USE_FROM_PTR (use_p); diff --git a/gcc/tree-outof-ssa.c b/gcc/tree-outof-ssa.c index d01c663b2c5..7cd5d92ef80 100644 --- a/gcc/tree-outof-ssa.c +++ b/gcc/tree-outof-ssa.c @@ -563,7 +563,7 @@ replace_use_variable (var_map map, use_operand_p p, tree *expr) SET_USE (p, new_expr); /* Clear the stmt's RHS, or GC might bite us. */ - GIMPLE_STMT_OPERAND (expr[version], 1) = NULL_TREE; + /* GIMPLE_STMT_OPERAND (expr[version], 1) = NULL_TREE; */ return true; } } @@ -918,11 +918,12 @@ analyze_edges_for_bb (basic_block bb) if (!bsi_end_p (bsi)) { stmt = bsi_stmt (bsi); - bsi_next (&bsi); + bsi_next_nondebug (&bsi); gcc_assert (stmt != NULL_TREE); is_label = (TREE_CODE (stmt) == LABEL_EXPR); /* Punt if it has non-label stmts, or isn't local. */ - if (!is_label || DECL_NONLOCAL (TREE_OPERAND (stmt, 0)) + if (((!is_label || DECL_NONLOCAL (TREE_OPERAND (stmt, 0))) + && !IS_DEBUG_STMT (stmt)) || !bsi_end_p (bsi)) { bsi_commit_one_edge_insert (e, NULL); diff --git a/gcc/tree-pretty-print.c b/gcc/tree-pretty-print.c index a7b97cdcb5c..77a6538c488 100644 --- a/gcc/tree-pretty-print.c +++ b/gcc/tree-pretty-print.c @@ -1101,6 +1101,19 @@ dump_generic_node (pretty_printer *buffer, tree node, int spc, int flags, false); break; + case VAR_DEBUG_VALUE: + pp_string (buffer, "# DEBUG "); + dump_generic_node (buffer, VAR_DEBUG_VALUE_VAR (node), spc, flags, false); + if (VAR_DEBUG_VALUE_VALUE (node) == VAR_DEBUG_VALUE_NOVALUE) + pp_string (buffer, " optimized away"); + else + { + pp_string (buffer, " = "); + dump_generic_node (buffer, VAR_DEBUG_VALUE_VALUE (node), spc, flags, + false); + } + break; + case TARGET_EXPR: pp_string (buffer, "TARGET_EXPR <"); dump_generic_node (buffer, TARGET_EXPR_SLOT (node), spc, flags, false); diff --git a/gcc/tree-ssa-alias.c b/gcc/tree-ssa-alias.c index 1ff3821ed5a..d3f8f8c3359 100644 --- a/gcc/tree-ssa-alias.c +++ b/gcc/tree-ssa-alias.c @@ -3908,6 +3908,10 @@ find_used_portions (tree *tp, int *walk_subtrees, void *lhs_p) { switch (TREE_CODE (*tp)) { + case VAR_DEBUG_VALUE: + *walk_subtrees = 0; + break; + case GIMPLE_MODIFY_STMT: /* Recurse manually here to track whether the use is in the LHS of an assignment. */ diff --git a/gcc/tree-ssa-coalesce.c b/gcc/tree-ssa-coalesce.c index ef1ebcab4a9..f682a9ff622 100644 --- a/gcc/tree-ssa-coalesce.c +++ b/gcc/tree-ssa-coalesce.c @@ -865,6 +865,8 @@ build_ssa_conflict_graph (tree_live_info_p liveinfo) if (TREE_CODE (lhs) == SSA_NAME && TREE_CODE (rhs) == SSA_NAME) live_track_clear_var (live, rhs); } + else if (IS_DEBUG_STMT (stmt)) + continue; FOR_EACH_SSA_TREE_OPERAND (var, stmt, iter, SSA_OP_DEF) live_track_process_def (live, var, graph); @@ -1027,6 +1029,9 @@ create_outofssa_var_map (coalesce_list_p cl, bitmap used_in_copy) { stmt = bsi_stmt (bsi); + if (IS_DEBUG_STMT (stmt)) + continue; + /* Register USE and DEF operands in each statement. */ FOR_EACH_SSA_TREE_OPERAND (var, stmt, iter, (SSA_OP_DEF|SSA_OP_USE)) register_ssa_partition (map, var); diff --git a/gcc/tree-ssa-dce.c b/gcc/tree-ssa-dce.c index bc1700338d8..574e44a489b 100644 --- a/gcc/tree-ssa-dce.c +++ b/gcc/tree-ssa-dce.c @@ -317,6 +317,10 @@ mark_stmt_if_obviously_necessary (tree stmt, bool aggressive) } break; + case VAR_DEBUG_VALUE: + mark_stmt_necessary (stmt, false); + return; + case GOTO_EXPR: gcc_assert (!simple_goto_p (stmt)); mark_stmt_necessary (stmt, true); @@ -653,6 +657,15 @@ remove_dead_stmt (block_stmt_iterator *i, basic_block bb) release_defs (t); } +/* Predicate used by check_and_update_debug_stmt. Return TRUE if the + T's definition is not about to be removed. T is assumed to be an + SSA_NAME. */ + +static bool +necessary_p (tree t) +{ + return NECESSARY (SSA_NAME_DEF_STMT (t)); +} /* Eliminate unnecessary statements. Any instruction not marked as necessary contributes nothing to the program, and can be deleted. */ @@ -691,8 +704,15 @@ eliminate_unnecessary_stmts (void) } else { - tree call = get_call_expr_in (t); - if (call) + tree call; + + if (TREE_CODE (t) == VAR_DEBUG_VALUE) + { + if (something_changed + && VAR_DEBUG_VALUE_VALUE (t) != VAR_DEBUG_VALUE_NOVALUE) + check_and_update_debug_stmt (t, necessary_p); + } + else if ((call = get_call_expr_in (t))) { tree name; diff --git a/gcc/tree-ssa-dom.c b/gcc/tree-ssa-dom.c index 7bed1c292d8..53ca66e6041 100644 --- a/gcc/tree-ssa-dom.c +++ b/gcc/tree-ssa-dom.c @@ -2233,6 +2233,8 @@ propagate_rhs_into_lhs (tree stmt, tree lhs, tree rhs, bitmap interesting_names) discard_stmt_changes (&use_stmt); continue; } + else if (IS_DEBUG_STMT (use_stmt)) + check_and_update_debug_stmt (use_stmt, NULL); /* From this point onward we are propagating into a real statement. Folding may (or may not) be possible, diff --git a/gcc/tree-ssa-forwprop.c b/gcc/tree-ssa-forwprop.c index 60e6ffa9e62..31cb70afd46 100644 --- a/gcc/tree-ssa-forwprop.c +++ b/gcc/tree-ssa-forwprop.c @@ -695,6 +695,7 @@ forward_propagate_addr_expr (tree name, tree rhs) tree 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) { @@ -704,7 +705,10 @@ forward_propagate_addr_expr (tree name, tree rhs) there is nothing we can do. */ if (TREE_CODE (use_stmt) != GIMPLE_MODIFY_STMT) { - all = false; + if (IS_DEBUG_STMT (use_stmt)) + debug = true; + else + all = false; continue; } @@ -738,6 +742,9 @@ forward_propagate_addr_expr (tree name, tree rhs) } } + if (all && debug) + adjust_debug_stmts_for_var_def_move (name, NULL, NULL); + return all; } diff --git a/gcc/tree-ssa-live.c b/gcc/tree-ssa-live.c index 4cf6620a759..a85da83a5e0 100644 --- a/gcc/tree-ssa-live.c +++ b/gcc/tree-ssa-live.c @@ -545,7 +545,8 @@ remove_unused_locals (void) /* Walk the statements. */ for (bsi = bsi_start (bb); !bsi_end_p (bsi); bsi_next (&bsi)) - mark_all_vars_used (bsi_stmt_ptr (bsi)); + if (TREE_CODE (bsi_stmt (bsi)) != VAR_DEBUG_VALUE) + mark_all_vars_used (bsi_stmt_ptr (bsi)); for (phi = phi_nodes (bb); phi; phi = PHI_CHAIN (phi)) { @@ -772,6 +773,8 @@ set_var_live_on_entry (tree ssa_name, tree_live_info_p live) add_block = e->src; } } + else if (IS_DEBUG_STMT (use_stmt)) + continue; else { /* If its not defined in this block, its live on entry. */ diff --git a/gcc/tree-ssa-loop-ch.c b/gcc/tree-ssa-loop-ch.c index ff62c686c28..958c6797326 100644 --- a/gcc/tree-ssa-loop-ch.c +++ b/gcc/tree-ssa-loop-ch.c @@ -83,6 +83,9 @@ should_duplicate_loop_header_p (basic_block header, struct loop *loop, if (TREE_CODE (last) == LABEL_EXPR) continue; + if (IS_DEBUG_STMT (last)) + continue; + if (get_call_expr_in (last)) return false; diff --git a/gcc/tree-ssa-loop-im.c b/gcc/tree-ssa-loop-im.c index d2ab41ce054..d2f624580b2 100644 --- a/gcc/tree-ssa-loop-im.c +++ b/gcc/tree-ssa-loop-im.c @@ -686,6 +686,7 @@ rewrite_bittest (block_stmt_iterator *bsi) SET_USE (use, name); bsi_insert_before (bsi, stmt1, BSI_SAME_STMT); + adjust_debug_stmts_for_move (bsi_stmt (*bsi), NULL, NULL); bsi_replace (bsi, stmt2, true); return stmt1; @@ -852,6 +853,7 @@ move_computations_stmt (struct dom_walk_data *dw_data ATTRIBUTE_UNUSED, cost, level->num); } bsi_insert_on_edge (loop_preheader_edge (level), stmt); + adjust_debug_stmts_for_move (bsi_stmt (bsi), NULL, NULL); bsi_remove (&bsi, false); } } diff --git a/gcc/tree-ssa-loop-ivopts.c b/gcc/tree-ssa-loop-ivopts.c index c8cefd418a1..7907fd69fae 100644 --- a/gcc/tree-ssa-loop-ivopts.c +++ b/gcc/tree-ssa-loop-ivopts.c @@ -1648,6 +1648,9 @@ find_interesting_uses_stmt (struct ivopts_data *data, tree stmt) if (TREE_CODE (op) != SSA_NAME) continue; + if (IS_DEBUG_STMT (USE_STMT (use_p))) + continue; + iv = get_iv (data, op); if (!iv) continue; @@ -5196,7 +5199,24 @@ remove_unused_ivs (struct ivopts_data *data) && !info->inv_id && !info->iv->have_use_for && !info->preserve_biv) - remove_statement (SSA_NAME_DEF_STMT (info->iv->ssa_name), true); + { + if (MAY_HAVE_DEBUG_STMTS) + { + tree stmt; + imm_use_iterator iter; + + FOR_EACH_IMM_USE_STMT (stmt, iter, info->iv->ssa_name) + { + if (!IS_DEBUG_STMT (stmt)) + continue; + + /* ??? We can probably do better than this. */ + VAR_DEBUG_VALUE_VALUE (stmt) = VAR_DEBUG_VALUE_NOVALUE; + update_stmt (stmt); + } + } + remove_statement (SSA_NAME_DEF_STMT (info->iv->ssa_name), true); + } } } diff --git a/gcc/tree-ssa-loop-manip.c b/gcc/tree-ssa-loop-manip.c index 91aac3eb354..a4ec6577b42 100644 --- a/gcc/tree-ssa-loop-manip.c +++ b/gcc/tree-ssa-loop-manip.c @@ -271,6 +271,9 @@ find_uses_to_rename_stmt (tree stmt, bitmap *use_blocks, bitmap need_phis) tree var; basic_block bb = bb_for_stmt (stmt); + if (IS_DEBUG_STMT (stmt)) + return; + FOR_EACH_SSA_TREE_OPERAND (var, stmt, iter, SSA_OP_ALL_USES) find_uses_to_rename_use (bb, var, use_blocks, need_phis); } @@ -422,6 +425,9 @@ check_loop_closed_ssa_stmt (basic_block bb, tree stmt) ssa_op_iter iter; tree var; + if (IS_DEBUG_STMT (stmt)) + return; + FOR_EACH_SSA_TREE_OPERAND (var, stmt, iter, SSA_OP_ALL_USES) check_loop_closed_ssa_use (bb, var); } diff --git a/gcc/tree-ssa-operands.c b/gcc/tree-ssa-operands.c index 3a944efa0b3..b798a85400d 100644 --- a/gcc/tree-ssa-operands.c +++ b/gcc/tree-ssa-operands.c @@ -126,6 +126,9 @@ static struct clobbering sites like function calls or ASM_EXPRs. */ #define opf_implicit (1 << 2) +/* Operand is a use only for purposes of debug information. */ +#define opf_debug_use (1 << 3) + /* Array for building all the def operands. */ static VEC(tree,heap) *build_defs; @@ -2057,6 +2060,7 @@ get_expr_operands (tree stmt, tree *expr_p, int flags) enum tree_code_class codeclass; tree expr = *expr_p; stmt_ann_t s_ann = stmt_ann (stmt); + int uflags = opf_use | (flags & opf_debug_use); if (expr == NULL) return; @@ -2071,7 +2075,9 @@ get_expr_operands (tree stmt, tree *expr_p, int flags) reference to it, but the fact that the statement takes its address will be of interest to some passes (e.g. alias resolution). */ - add_to_addressable_set (TREE_OPERAND (expr, 0), &s_ann->addresses_taken); + if (!(flags & opf_debug_use)) + add_to_addressable_set (TREE_OPERAND (expr, 0), + &s_ann->addresses_taken); /* If the address is invariant, there may be no interesting variable references inside. */ @@ -2190,13 +2196,13 @@ get_expr_operands (tree stmt, tree *expr_p, int flags) { if (TREE_THIS_VOLATILE (TREE_OPERAND (expr, 1))) s_ann->has_volatile_ops = true; - get_expr_operands (stmt, &TREE_OPERAND (expr, 2), opf_use); + get_expr_operands (stmt, &TREE_OPERAND (expr, 2), uflags); } else if (code == ARRAY_REF || code == ARRAY_RANGE_REF) { - get_expr_operands (stmt, &TREE_OPERAND (expr, 1), opf_use); - get_expr_operands (stmt, &TREE_OPERAND (expr, 2), opf_use); - get_expr_operands (stmt, &TREE_OPERAND (expr, 3), opf_use); + get_expr_operands (stmt, &TREE_OPERAND (expr, 1), uflags); + get_expr_operands (stmt, &TREE_OPERAND (expr, 2), uflags); + get_expr_operands (stmt, &TREE_OPERAND (expr, 3), uflags); } return; @@ -2205,7 +2211,7 @@ get_expr_operands (tree stmt, tree *expr_p, int flags) case WITH_SIZE_EXPR: /* WITH_SIZE_EXPR is a pass-through reference to its first argument, and an rvalue reference to its second argument. */ - get_expr_operands (stmt, &TREE_OPERAND (expr, 1), opf_use); + get_expr_operands (stmt, &TREE_OPERAND (expr, 1), uflags); get_expr_operands (stmt, &TREE_OPERAND (expr, 0), flags); return; @@ -2215,15 +2221,21 @@ get_expr_operands (tree stmt, tree *expr_p, int flags) case COND_EXPR: case VEC_COND_EXPR: - get_expr_operands (stmt, &TREE_OPERAND (expr, 0), opf_use); - get_expr_operands (stmt, &TREE_OPERAND (expr, 1), opf_use); - get_expr_operands (stmt, &TREE_OPERAND (expr, 2), opf_use); + get_expr_operands (stmt, &TREE_OPERAND (expr, 0), uflags); + get_expr_operands (stmt, &TREE_OPERAND (expr, 1), uflags); + get_expr_operands (stmt, &TREE_OPERAND (expr, 2), uflags); return; case GIMPLE_MODIFY_STMT: get_modify_stmt_operands (stmt, expr); return; + case VAR_DEBUG_VALUE: + if (VAR_DEBUG_VALUE_VALUE (stmt) != VAR_DEBUG_VALUE_NOVALUE) + get_expr_operands (stmt, &VAR_DEBUG_VALUE_VALUE (stmt), + opf_use | opf_debug_use); + return; + case CONSTRUCTOR: { /* General aggregate CONSTRUCTORs have been decomposed, but they @@ -2234,7 +2246,7 @@ get_expr_operands (tree stmt, tree *expr_p, int flags) for (idx = 0; VEC_iterate (constructor_elt, CONSTRUCTOR_ELTS (expr), idx, ce); idx++) - get_expr_operands (stmt, &ce->value, opf_use); + get_expr_operands (stmt, &ce->value, uflags); return; } @@ -2269,7 +2281,7 @@ get_expr_operands (tree stmt, tree *expr_p, int flags) } case CHANGE_DYNAMIC_TYPE_EXPR: - get_expr_operands (stmt, &CHANGE_DYNAMIC_TYPE_LOCATION (expr), opf_use); + get_expr_operands (stmt, &CHANGE_DYNAMIC_TYPE_LOCATION (expr), uflags); return; case OMP_FOR: @@ -2375,6 +2387,12 @@ parse_ssa_operands (tree stmt) get_modify_stmt_operands (stmt, stmt); break; + case VAR_DEBUG_VALUE: + if (VAR_DEBUG_VALUE_VALUE (stmt) != VAR_DEBUG_VALUE_NOVALUE) + get_expr_operands (stmt, &VAR_DEBUG_VALUE_VALUE (stmt), + opf_use | opf_debug_use); + return; + case COND_EXPR: get_expr_operands (stmt, &COND_EXPR_COND (stmt), opf_use); break; diff --git a/gcc/tree-ssa-phiopt.c b/gcc/tree-ssa-phiopt.c index a8376cf5885..4b356a668f2 100644 --- a/gcc/tree-ssa-phiopt.c +++ b/gcc/tree-ssa-phiopt.c @@ -387,7 +387,8 @@ empty_block_p (basic_block bb) bsi = bsi_start (bb); while (!bsi_end_p (bsi) && (TREE_CODE (bsi_stmt (bsi)) == LABEL_EXPR - || IS_EMPTY_STMT (bsi_stmt (bsi)))) + || IS_EMPTY_STMT (bsi_stmt (bsi)) + || IS_DEBUG_STMT (bsi_stmt (bsi)))) bsi_next (&bsi); if (!bsi_end_p (bsi)) diff --git a/gcc/tree-ssa-pre.c b/gcc/tree-ssa-pre.c index 33c44ee0d1b..0bde7aeb677 100644 --- a/gcc/tree-ssa-pre.c +++ b/gcc/tree-ssa-pre.c @@ -3553,7 +3553,6 @@ compute_avail (void) } continue; } - else if (TREE_CODE (stmt) == GIMPLE_MODIFY_STMT && !ann->has_volatile_ops && TREE_CODE (GIMPLE_STMT_OPERAND (stmt, 0)) == SSA_NAME @@ -3562,8 +3561,9 @@ compute_avail (void) { if (make_values_for_stmt (stmt, block)) continue; - } + else if (IS_DEBUG_STMT (stmt)) + continue; /* For any other statement that we don't recognize, simply make the names generated by the statement available in diff --git a/gcc/tree-ssa-propagate.c b/gcc/tree-ssa-propagate.c index 17eec742138..490a83710ee 100644 --- a/gcc/tree-ssa-propagate.c +++ b/gcc/tree-ssa-propagate.c @@ -557,6 +557,9 @@ get_rhs (tree stmt) else return stmt; + case VAR_DEBUG_VALUE: + return VAR_DEBUG_VALUE_VALUE (stmt); + case COND_EXPR: return COND_EXPR_COND (stmt); case SWITCH_EXPR: diff --git a/gcc/tree-ssa-reassoc.c b/gcc/tree-ssa-reassoc.c index 200088d7dd4..b0baf279b44 100644 --- a/gcc/tree-ssa-reassoc.c +++ b/gcc/tree-ssa-reassoc.c @@ -945,6 +945,7 @@ linearize_expr (tree stmt) bsinow = bsi_for_stmt (stmt); bsirhs = bsi_for_stmt (binrhs); + adjust_debug_stmts_for_move (binrhs, bb_for_stmt (stmt), &bsinow); bsi_move_before (&bsirhs, &bsinow); TREE_OPERAND (rhs, 1) = TREE_OPERAND (GIMPLE_STMT_OPERAND (binrhs, 1), 0); @@ -1174,6 +1175,8 @@ linearize_expr_tree (VEC(operand_entry_t, heap) **ops, tree stmt) rhscode, loop)); bsinow = bsi_for_stmt (stmt); bsilhs = bsi_for_stmt (SSA_NAME_DEF_STMT (binlhs)); + adjust_debug_stmts_for_move (SSA_NAME_DEF_STMT (binlhs), + bb_for_stmt (stmt), &bsinow); bsi_move_before (&bsilhs, &bsinow); linearize_expr_tree (ops, SSA_NAME_DEF_STMT (binlhs)); add_to_ops_vec (ops, binrhs); diff --git a/gcc/tree-ssa-sink.c b/gcc/tree-ssa-sink.c index cd57baa0d99..bb88bdfef29 100644 --- a/gcc/tree-ssa-sink.c +++ b/gcc/tree-ssa-sink.c @@ -119,6 +119,8 @@ all_immediate_uses_same_place (tree stmt) { FOR_EACH_IMM_USE_FAST (use_p, imm_iter, var) { + if (IS_DEBUG_STMT (USE_STMT (use_p))) + continue; if (firstuse == NULL_TREE) firstuse = USE_STMT (use_p); else @@ -213,7 +215,7 @@ is_hidden_global_store (tree stmt) /* Find the nearest common dominator of all of the immediate uses in IMM. */ static basic_block -nearest_common_dominator_of_uses (tree stmt) +nearest_common_dominator_of_uses (tree stmt, bool *debug_stmts) { bitmap blocks = BITMAP_ALLOC (NULL); basic_block commondom; @@ -238,6 +240,11 @@ nearest_common_dominator_of_uses (tree stmt) useblock = PHI_ARG_EDGE (usestmt, idx)->src; } + else if (IS_DEBUG_STMT (usestmt)) + { + *debug_stmts = true; + continue; + } else { useblock = bb_for_stmt (usestmt); @@ -284,6 +291,9 @@ statement_sink_location (tree stmt, basic_block frombb, basic_block *tobb, { FOR_EACH_IMM_USE_FAST (one_use, imm_iter, def) { + if (IS_DEBUG_STMT (USE_STMT (one_use))) + continue; + break; } if (one_use != NULL_USE_OPERAND_P) @@ -349,7 +359,9 @@ statement_sink_location (tree stmt, basic_block frombb, basic_block *tobb, that is where insertion would have to take place. */ if (!all_immediate_uses_same_place (stmt)) { - basic_block commondom = nearest_common_dominator_of_uses (stmt); + bool debug_stmts = false; + basic_block commondom = nearest_common_dominator_of_uses (stmt, + &debug_stmts); if (commondom == frombb) return false; @@ -378,8 +390,13 @@ statement_sink_location (tree stmt, basic_block frombb, basic_block *tobb, fprintf (dump_file, "Common dominator of all uses is %d\n", commondom->index); } + *tobb = commondom; *tobsi = bsi_after_labels (commondom); + + if (debug_stmts) + adjust_debug_stmts_for_move (stmt, *tobb, tobsi); + return true; } @@ -392,6 +409,9 @@ statement_sink_location (tree stmt, basic_block frombb, basic_block *tobb, return false; *tobb = sinkbb; *tobsi = bsi_for_stmt (use); + + adjust_debug_stmts_for_move (stmt, *tobb, tobsi); + return true; } @@ -421,6 +441,8 @@ statement_sink_location (tree stmt, basic_block frombb, basic_block *tobb, *tobb = sinkbb; *tobsi = bsi_after_labels (sinkbb); + adjust_debug_stmts_for_move (stmt, *tobb, tobsi); + return true; } diff --git a/gcc/tree-ssa-structalias.c b/gcc/tree-ssa-structalias.c index e2019f5e3f2..78191fcd3ba 100644 --- a/gcc/tree-ssa-structalias.c +++ b/gcc/tree-ssa-structalias.c @@ -5373,7 +5373,8 @@ compute_points_to_sets (struct alias_info *ai) addresses, pointer dereferences for loads and stores. This is used when creating name tags and alias sets. */ - update_alias_info (stmt, ai); + if (!IS_DEBUG_STMT (stmt)) + update_alias_info (stmt, ai); /* The information in CHANGE_DYNAMIC_TYPE_EXPR nodes has now been captured, and we can remove them. */ diff --git a/gcc/tree-ssa-ter.c b/gcc/tree-ssa-ter.c index f0fef24aa4a..27fbaad9eb9 100644 --- a/gcc/tree-ssa-ter.c +++ b/gcc/tree-ssa-ter.c @@ -562,6 +562,10 @@ find_replaceable_in_bb (temp_expr_table_p tab, basic_block bb) for (bsi = bsi_start (bb); !bsi_end_p (bsi); bsi_next (&bsi)) { stmt = bsi_stmt (bsi); + + if (IS_DEBUG_STMT (stmt)) + continue; + ann = stmt_ann (stmt); stmt_replaceable = is_replaceable_p (stmt); diff --git a/gcc/tree-ssa-threadedge.c b/gcc/tree-ssa-threadedge.c index 9e7dd6eed56..3235ebcbcf0 100644 --- a/gcc/tree-ssa-threadedge.c +++ b/gcc/tree-ssa-threadedge.c @@ -230,7 +230,8 @@ record_temporary_equivalences_from_stmts_at_dest (edge e, stmt = bsi_stmt (bsi); /* Ignore empty statements and labels. */ - if (IS_EMPTY_STMT (stmt) || TREE_CODE (stmt) == LABEL_EXPR) + if (IS_EMPTY_STMT (stmt) || IS_DEBUG_STMT (stmt) + || TREE_CODE (stmt) == LABEL_EXPR) continue; /* If the statement has volatile operands, then we assume we diff --git a/gcc/tree-ssa-threadupdate.c b/gcc/tree-ssa-threadupdate.c index 1d5500fe018..560249a1483 100644 --- a/gcc/tree-ssa-threadupdate.c +++ b/gcc/tree-ssa-threadupdate.c @@ -469,7 +469,8 @@ redirection_block_p (basic_block bb) bsi = bsi_start (bb); while (!bsi_end_p (bsi) && (TREE_CODE (bsi_stmt (bsi)) == LABEL_EXPR - || IS_EMPTY_STMT (bsi_stmt (bsi)))) + || IS_EMPTY_STMT (bsi_stmt (bsi)) + || IS_DEBUG_STMT (bsi_stmt (bsi)))) bsi_next (&bsi); /* Check if this is an empty block. */ diff --git a/gcc/tree-ssa.c b/gcc/tree-ssa.c index 9723afb0eec..8e481494402 100644 --- a/gcc/tree-ssa.c +++ b/gcc/tree-ssa.c @@ -699,6 +699,9 @@ verify_ssa (bool check_modified_stmt) goto err; } } + else if (TREE_CODE (stmt) == VAR_DEBUG_VALUE + && VAR_DEBUG_VALUE_VALUE (stmt) == VAR_DEBUG_VALUE_NOVALUE) + continue; FOR_EACH_SSA_TREE_OPERAND (op, stmt, iter, SSA_OP_ALL_VIRTUALS) { @@ -1316,6 +1319,10 @@ execute_early_warn_uninitialized (void) for (bsi = bsi_start (bb); !bsi_end_p (bsi); bsi_next (&bsi)) { tree context = bsi_stmt (bsi); + + if (TREE_CODE (context) == VAR_DEBUG_VALUE) + continue; + walk_tree (bsi_stmt_ptr (bsi), warn_uninitialized_var, context, NULL); } diff --git a/gcc/tree-ssanames.c b/gcc/tree-ssanames.c index 956dd00206d..3f145a9db1d 100644 --- a/gcc/tree-ssanames.c +++ b/gcc/tree-ssanames.c @@ -203,6 +203,9 @@ release_ssa_name (tree var) int saved_ssa_name_version = SSA_NAME_VERSION (var); use_operand_p imm = &(SSA_NAME_IMM_USE_NODE (var)); + if (MAY_HAVE_DEBUG_STMTS) + adjust_debug_stmts_for_var_def_move (var, NULL, NULL); + #ifdef ENABLE_CHECKING verify_imm_links (stderr, var); #endif diff --git a/gcc/tree-stdarg.c b/gcc/tree-stdarg.c index 168bd2f1564..6a175c73378 100644 --- a/gcc/tree-stdarg.c +++ b/gcc/tree-stdarg.c @@ -850,6 +850,8 @@ execute_optimize_stdarg (void) continue; } } + else if (IS_DEBUG_STMT (stmt)) + continue; /* All other uses of va_list are either va_copy (that is not handled in this optimization), taking address of va_list variable or diff --git a/gcc/tree-tailcall.c b/gcc/tree-tailcall.c index bd3da886668..7dafa56e9a8 100644 --- a/gcc/tree-tailcall.c +++ b/gcc/tree-tailcall.c @@ -391,7 +391,7 @@ find_tail_calls (basic_block bb, struct tailcall **ret) stmt = bsi_stmt (bsi); /* Ignore labels. */ - if (TREE_CODE (stmt) == LABEL_EXPR) + if (TREE_CODE (stmt) == LABEL_EXPR || IS_DEBUG_STMT (stmt)) continue; /* Check for a call. */ @@ -495,6 +495,9 @@ find_tail_calls (basic_block bb, struct tailcall **ret) if (TREE_CODE (stmt) == RETURN_EXPR) break; + if (IS_DEBUG_STMT (stmt)) + continue; + if (TREE_CODE (stmt) != GIMPLE_MODIFY_STMT) return; diff --git a/gcc/tree-vrp.c b/gcc/tree-vrp.c index dfb28203948..b8e0d5256aa 100644 --- a/gcc/tree-vrp.c +++ b/gcc/tree-vrp.c @@ -4067,6 +4067,9 @@ find_assert_locations (basic_block bb) stmt = bsi_stmt (si); + if (IS_DEBUG_STMT (stmt)) + continue; + /* See if we can derive an assertion for any of STMT's operands. */ FOR_EACH_SSA_TREE_OPERAND (op, stmt, i, SSA_OP_USE) { diff --git a/gcc/tree.c b/gcc/tree.c index 88ec29e13e3..79b4e58f5fe 100644 --- a/gcc/tree.c +++ b/gcc/tree.c @@ -3160,6 +3160,21 @@ build_gimple_modify_stmt_stat (tree arg0, tree arg1 MEM_STAT_DECL) return t; } +/* Build a VAR_DEBUG_VALUE node. This tree code doesn't have a + type, so we can't use build2 (a.k.a. build2_stat). */ + +tree +build_var_debug_value_stat (tree arg0, tree arg1 MEM_STAT_DECL) +{ + tree t; + + t = make_node_stat (VAR_DEBUG_VALUE PASS_MEM_STAT); + /* ?? We don't care about setting flags for tuples... */ + VAR_DEBUG_VALUE_SET_VAR (t, arg0); + VAR_DEBUG_VALUE_VALUE (t) = arg1; + return t; +} + tree build3_stat (enum tree_code code, tree tt, tree arg0, tree arg1, tree arg2 MEM_STAT_DECL) @@ -8647,7 +8662,7 @@ empty_body_p (tree stmt) tree_stmt_iterator i; tree body; - if (IS_EMPTY_STMT (stmt)) + if (IS_EMPTY_STMT (stmt) || IS_DEBUG_STMT (stmt)) return true; else if (TREE_CODE (stmt) == BIND_EXPR) body = BIND_EXPR_BODY (stmt); diff --git a/gcc/tree.def b/gcc/tree.def index b9c2be1648c..7d7904c597e 100644 --- a/gcc/tree.def +++ b/gcc/tree.def @@ -1110,6 +1110,10 @@ DEFTREECODE (VEC_RSHIFT_EXPR, "vec_rshift_expr", tcc_binary, 2) /* Assignment expression. Operand 0 is the what to set; 1, the new value. */ DEFTREECODE (GIMPLE_MODIFY_STMT, "gimple_modify_stmt", tcc_gimple_stmt, 2) +/* Debug annotation. Operand 0 is a user variable; 1 is an expression + with its value, for purposes of debug information. */ +DEFTREECODE (VAR_DEBUG_VALUE, "var_debug_value", tcc_gimple_stmt, 2) + /* Widening vector multiplication. The two operands are vectors with N elements of size S. Multiplying the elements of the two vectors will result in N products of size 2*S. diff --git a/gcc/tree.h b/gcc/tree.h index 55b31912370..62e5589731c 100644 --- a/gcc/tree.h +++ b/gcc/tree.h @@ -829,6 +829,32 @@ enum tree_node_structure_enum { __FILE__, __LINE__, __FUNCTION__); \ &__t->gstmt.operands[__i]; })) +/* Set the variable set by the VAR_DEBUG_VALUE stmt. */ +#define VAR_DEBUG_VALUE_SET_VAR(T, V) __extension__ \ + ({const tree __t = VAR_DEBUG_VALUE_CHECK (T); \ + if (0 >= TREE_OPERAND_LENGTH (__t)) \ + tree_operand_check_failed (0, __t, \ + __FILE__, __LINE__, __FUNCTION__); \ + __t->gstmt.operands[0] = (V); }) + +/* Rvalue for the variable set by the VAR_DEBUG_VALUE stmt. */ +#define VAR_DEBUG_VALUE_VAR(T) __extension__ \ + ({const tree __t = VAR_DEBUG_VALUE_CHECK (T); \ + tree __var; \ + if (0 >= TREE_OPERAND_LENGTH (__t)) \ + tree_operand_check_failed (0, __t, \ + __FILE__, __LINE__, __FUNCTION__); \ + __var = __t->gstmt.operands[0]; \ + __var; }) + +/* Lvalue for the value of the variable. */ +#define VAR_DEBUG_VALUE_VALUE(T) __extension__ \ +(*({const tree __t = VAR_DEBUG_VALUE_CHECK (T); \ + if (1 >= TREE_OPERAND_LENGTH (__t)) \ + tree_operand_check_failed (1, __t, \ + __FILE__, __LINE__, __FUNCTION__); \ + &__t->gstmt.operands[1]; })) + #define TREE_RTL_OPERAND_CHECK(T, CODE, I) __extension__ \ (*(rtx *) \ ({__typeof (T) const __t = (T); \ @@ -926,6 +952,9 @@ extern void omp_clause_range_check_failed (const_tree, const char *, int, #define TREE_OPERAND_CHECK(T, I) ((T)->exp.operands[I]) #define TREE_OPERAND_CHECK_CODE(T, CODE, I) ((T)->exp.operands[I]) #define GIMPLE_STMT_OPERAND_CHECK(T, I) ((T)->gstmt.operands[I]) +#define VAR_DEBUG_VALUE_SET_VAR(T, V) ((T)->gstmt.operands[0] = (V)) +#define VAR_DEBUG_VALUE_VAR(T) ((tree)(T)->gstmt.operands[0]) +#define VAR_DEBUG_VALUE_VALUE(T) ((T)->gstmt.operands[1]) #define TREE_RTL_OPERAND_CHECK(T, CODE, I) (*(rtx *) &((T)->exp.operands[I])) #define PHI_NODE_ELT_CHECK(T, i) ((T)->phi.a[i]) #define OMP_CLAUSE_ELT_CHECK(T, i) ((T)->omp_clause.ops[i]) @@ -1572,6 +1601,12 @@ struct tree_constructor GTY(()) && VOID_TYPE_P (TREE_TYPE (NODE)) \ && integer_zerop (TREE_OPERAND (NODE, 0))) +/* Nonzero if NODE is a debug statement (VAR_DEBUG_VALUE). */ +#define IS_DEBUG_STMT(NODE) (TREE_CODE (NODE) == VAR_DEBUG_VALUE) + +/* Nonzero if IS_DEBUG_STMT may possibly. */ +#define MAY_HAVE_DEBUG_STMTS (flag_var_tracking_assignments) + /* In ordinary expression nodes. */ #define TREE_OPERAND_LENGTH(NODE) tree_operand_length (NODE) #define TREE_OPERAND(NODE, I) TREE_OPERAND_CHECK (NODE, I) @@ -1589,6 +1624,10 @@ struct tree_constructor GTY(()) #define GIMPLE_STMT_LOCUS(NODE) (GIMPLE_STMT_CHECK (NODE)->gstmt.locus) #define GIMPLE_STMT_BLOCK(NODE) (GIMPLE_STMT_CHECK (NODE)->gstmt.block) +/* The second operand of a VAR_DEBUG_VALUE when the value was + optimized away. */ +#define VAR_DEBUG_VALUE_NOVALUE NULL_TREE /* error_mark_node */ + /* In a LOOP_EXPR node. */ #define LOOP_EXPR_BODY(NODE) TREE_OPERAND_CHECK_CODE (NODE, LOOP_EXPR, 0) @@ -3950,6 +3989,10 @@ extern tree build_gimple_modify_stmt_stat (tree, tree MEM_STAT_DECL); #define build_gimple_modify_stmt(t1,t2) \ build_gimple_modify_stmt_stat (t1,t2 MEM_STAT_INFO) +extern tree build_var_debug_value_stat (tree, tree MEM_STAT_DECL); +#define build_var_debug_value(t1,t2) \ + build_var_debug_value_stat (t1,t2 MEM_STAT_INFO) + extern tree build_int_cst (tree, HOST_WIDE_INT); extern tree build_int_cst_type (tree, HOST_WIDE_INT); extern tree build_int_cstu (tree, unsigned HOST_WIDE_INT); @@ -5351,4 +5394,8 @@ more_const_call_expr_args_p (const const_call_expr_arg_iterator *iter) for ((arg) = first_const_call_expr_arg ((call), &(iter)); (arg); \ (arg) = next_const_call_expr_arg (&(iter))) +/* Determines whether the given TREE is subject to debug tracking. */ + +bool var_debug_value_for_decl (tree); + #endif /* GCC_TREE_H */ |