From 2a02ebc79b51693a341355a2301dc0f733591930 Mon Sep 17 00:00:00 2001 From: Pierre-Marie de Rodat Date: Thu, 13 Jun 2013 11:13:08 +0200 Subject: [PATCH] Track indirect calls for call site information in debug info. gcc/ChangeLog: * passes.def: Add a new pass: variable_tracking_no_opt. * rtl.h (variable_tracking_no_opt_main): New. * tree-pass.h (make_pass_variable_tracking_no_opt): New. * var-tracking.c (variable_tracking_no_opt_main, pass_data_variable_tracking_no_opt, pass_variable_tracking_no_opt, make_pass_variable_tracking_no_opt): New. Implement the new pass which adds notes for indirect calls. * dwarf2out.c (dwarf2out_var_location): Set the symbol reference for calls whose target is compile-time known but that are indirect. (gen_subprogram_die): Handle such calls. --- gcc/dwarf2out.c | 46 +++++++++++++++--------- gcc/passes.def | 1 + gcc/rtl.h | 1 + gcc/tree-pass.h | 1 + gcc/var-tracking.c | 102 +++++++++++++++++++++++++++++++++++++++++++++++++++++ 5 files changed, 135 insertions(+), 16 deletions(-) diff --git a/gcc/dwarf2out.c b/gcc/dwarf2out.c index f184750..c8c37ff 100644 --- a/gcc/dwarf2out.c +++ b/gcc/dwarf2out.c @@ -19277,18 +19277,23 @@ gen_subprogram_die (tree decl, dw_die_ref context_die) } if (mode == VOIDmode || mode == BLKmode) continue; - if (XEXP (XEXP (arg, 0), 0) == pc_rtx) + /* Sometimes, the target of a call is compile-time known, but + for various reasons, there is still an indirect call + instruction: do not output redundant debug information for + them. */ + if (ca_loc->symbol_ref == NULL_RTX) { - gcc_assert (ca_loc->symbol_ref == NULL_RTX); - tloc = XEXP (XEXP (arg, 0), 1); - continue; - } - else if (GET_CODE (XEXP (XEXP (arg, 0), 0)) == CLOBBER - && XEXP (XEXP (XEXP (arg, 0), 0), 0) == pc_rtx) - { - gcc_assert (ca_loc->symbol_ref == NULL_RTX); - tlocc = XEXP (XEXP (arg, 0), 1); - continue; + if (XEXP (XEXP (arg, 0), 0) == pc_rtx) + { + tloc = XEXP (XEXP (arg, 0), 1); + continue; + } + else if (GET_CODE (XEXP (XEXP (arg, 0), 0)) == CLOBBER + && XEXP (XEXP (XEXP (arg, 0), 0), 0) == pc_rtx) + { + tlocc = XEXP (XEXP (arg, 0), 1); + continue; + } } reg = NULL; if (REG_P (XEXP (XEXP (arg, 0), 0))) @@ -22428,11 +22433,20 @@ dwarf2out_var_location (rtx_insn *loc_note) x = get_call_rtx_from (PATTERN (prev)); if (x) { - x = XEXP (XEXP (x, 0), 0); - if (GET_CODE (x) == SYMBOL_REF - && SYMBOL_REF_DECL (x) - && TREE_CODE (SYMBOL_REF_DECL (x)) == FUNCTION_DECL) - ca_loc->symbol_ref = x; + /* Try to get the call symbol, if any. */ + if (MEM_P (XEXP (x, 0))) + x = XEXP (x, 0); + /* First, look for a memory access to a symbol_ref. */ + if (GET_CODE (XEXP (x, 0)) == SYMBOL_REF + && SYMBOL_REF_DECL (XEXP (x, 0)) + && TREE_CODE (SYMBOL_REF_DECL (XEXP (x, 0))) == FUNCTION_DECL) + ca_loc->symbol_ref = XEXP (x, 0); + /* Otherwise, look at a compile-time known user-level function + declaration. */ + else if (MEM_P (x) + && MEM_EXPR (x) + && TREE_CODE (MEM_EXPR (x)) == FUNCTION_DECL) + ca_loc->symbol_ref = XEXP (DECL_RTL (MEM_EXPR (x)), 0); } ca_loc->block = insn_scope (prev); if (call_arg_locations) diff --git a/gcc/passes.def b/gcc/passes.def index 1702778..2c4ecc6 100644 --- a/gcc/passes.def +++ b/gcc/passes.def @@ -449,6 +449,7 @@ along with GCC; see the file COPYING3. If not see PUSH_INSERT_PASSES_WITHIN (pass_late_compilation) NEXT_PASS (pass_compute_alignments); NEXT_PASS (pass_variable_tracking); + NEXT_PASS (pass_variable_tracking_no_opt); NEXT_PASS (pass_free_cfg); NEXT_PASS (pass_machine_reorg); NEXT_PASS (pass_cleanup_barriers); diff --git a/gcc/rtl.h b/gcc/rtl.h index 194ed9b..7f54605 100644 --- a/gcc/rtl.h +++ b/gcc/rtl.h @@ -3673,6 +3673,7 @@ extern GTY(()) rtx stack_limit_rtx; /* In var-tracking.c */ extern unsigned int variable_tracking_main (void); +extern unsigned int variable_tracking_no_opt_main (void); /* In stor-layout.c. */ extern void get_mode_bounds (machine_mode, int, machine_mode, diff --git a/gcc/tree-pass.h b/gcc/tree-pass.h index dcd2d5e..33d9218 100644 --- a/gcc/tree-pass.h +++ b/gcc/tree-pass.h @@ -589,6 +589,7 @@ extern rtl_opt_pass *make_pass_df_finish (gcc::context *ctxt); extern rtl_opt_pass *make_pass_compute_alignments (gcc::context *ctxt); extern rtl_opt_pass *make_pass_duplicate_computed_gotos (gcc::context *ctxt); extern rtl_opt_pass *make_pass_variable_tracking (gcc::context *ctxt); +extern rtl_opt_pass *make_pass_variable_tracking_no_opt (gcc::context *ctxt); extern rtl_opt_pass *make_pass_free_cfg (gcc::context *ctxt); extern rtl_opt_pass *make_pass_machine_reorg (gcc::context *ctxt); extern rtl_opt_pass *make_pass_cleanup_barriers (gcc::context *ctxt); diff --git a/gcc/var-tracking.c b/gcc/var-tracking.c index 9185bfd..2103d87 100644 --- a/gcc/var-tracking.c +++ b/gcc/var-tracking.c @@ -114,6 +114,7 @@ #include "tree-pretty-print.h" #include "rtl-iter.h" #include "fibonacci_heap.h" +#include "debug.h" typedef fibonacci_heap bb_heap_t; typedef fibonacci_node bb_heap_node_t; @@ -10284,6 +10285,61 @@ variable_tracking_main (void) return ret; } +/* Entry point for the naive variable tracking pass. Add notes for indirect + calls in each basic block. */ + +unsigned int +variable_tracking_no_opt_main (void) +{ + basic_block bb; + + /* Look for every call instruction and add an empty note right after + them if needed. */ + FOR_EACH_BB_FN (bb, cfun) + { + rtx_insn *insn; + + FOR_BB_INSNS (bb, insn) + { + rtx x; + + /* We are at -O0 so do not bother about dealing with SEQUENCEs. */ + if (!INSN_P (insn)) + continue; + x = PATTERN (insn); + if (GET_CODE (x) == PARALLEL) + x = XVECEXP (x, 0, 0); + if (GET_CODE (x) == SET) + x = SET_SRC (x); + if (GET_CODE (x) == CALL) + { + x = XEXP (x, 0); + + /* The purpose of this pass is to add notes after some call + instructions so that debug info is generated for them. The + goal is to make it possible to get the call target by looking + either at the call instruction or, when this is not sufficient + (like with indirect calls), at the corresponding debug + information. */ + if (!MEM_P (x) + || GET_CODE (XEXP (x, 0)) != SYMBOL_REF + || !SYMBOL_REF_DECL (XEXP (x, 0)) + || (TREE_CODE (SYMBOL_REF_DECL (XEXP (x, 0))) + != FUNCTION_DECL)) + { + /* Emit a not only for calls that have a pattern that is not: + (call (mem (symbol_ref some_function_decl))). */ + rtx note + = emit_note_after (NOTE_INSN_CALL_ARG_LOCATION, insn); + NOTE_VAR_LOCATION (note) = NULL; + } + } + } + } + + return 0; +} + namespace { const pass_data pass_data_variable_tracking = @@ -10319,6 +10375,46 @@ public: }; // class pass_variable_tracking +const pass_data pass_data_variable_tracking_no_opt = +{ + RTL_PASS, /* type */ + "no-opt vartrack", /* name */ + OPTGROUP_NONE, /* optinfo_flags */ + TV_VAR_TRACKING,/* tv_id */ + 0, /* properties_required */ + 0, /* properties_provided */ + 0, /* properties_destroyed */ + 0, /* todo_flags_start */ + 0 /* todo_flags_finish */ +}; + +class pass_variable_tracking_no_opt : public rtl_opt_pass +{ +public: + pass_variable_tracking_no_opt (gcc::context *ctxt) + : rtl_opt_pass (pass_data_variable_tracking_no_opt, ctxt) + {} + + /* opt_pass methods: */ + virtual bool gate (function *) + { + /* This pass replaces the regular var-tracking pass when it is not + enabled, but only at -O0 (by default, the var-tracking pass is + disabled at -O0 only). It is useful only when producing debug + information. */ + return (optimize == 0 + && !flag_var_tracking + && debug_info_level >= DINFO_LEVEL_NORMAL + && (debug_hooks->var_location + != do_nothing_debug_hooks.var_location)); + } + + virtual unsigned int execute (function *) + { + return variable_tracking_no_opt_main (); + } +}; // class pass_variable_tracking_no_opt + } // anon namespace rtl_opt_pass * @@ -10326,3 +10422,9 @@ make_pass_variable_tracking (gcc::context *ctxt) { return new pass_variable_tracking (ctxt); } + +rtl_opt_pass * +make_pass_variable_tracking_no_opt (gcc::context *ctxt) +{ + return new pass_variable_tracking_no_opt (ctxt); +} -- 2.3.3.199.g52cae64