diff mbox

[PING*4] Track indirect calls for call site information in debug info.

Message ID 565490CF.9000101@adacore.com
State New
Headers show

Commit Message

Pierre-Marie de Rodat Nov. 24, 2015, 4:31 p.m. UTC
On 11/23/2015 10:11 PM, Jason Merrill wrote:
> Jakub, since DW_TAG_GNU_call_site is your feature, could you review this?

As Jeff Law suggested in the “GCC 6 Status Report” thread, I’ve added 
Alexandre Oliva to the discussion to review the var-tracking part.

Also, I’ve rebased+bootstrapped+regtested the patch: the updated version 
is attached.

Thanks in advance for your review!

Comments

Jakub Jelinek Nov. 24, 2015, 5:10 p.m. UTC | #1
On Tue, Nov 24, 2015 at 05:31:11PM +0100, Pierre-Marie de Rodat wrote:
> On 11/23/2015 10:11 PM, Jason Merrill wrote:
> >Jakub, since DW_TAG_GNU_call_site is your feature, could you review this?
> 
> As Jeff Law suggested in the “GCC 6 Status Report” thread, I’ve added
> Alexandre Oliva to the discussion to review the var-tracking part.
> 
> Also, I’ve rebased+bootstrapped+regtested the patch: the updated version is
> attached.
> 
> Thanks in advance for your review!

The new pass is IMNSHO completely useless and undesirable, both for compile
time (another whole IL traversal) reasons and for the unnecessary creation
of memory allocations.
final.c already calls dwarf2out_var_location on all calls, so you can
do is just add some code there:
       if (CALL_P (loc_note))
 	{
 	  call_site_count++;
 	  if (SIBLING_CALL_P (loc_note))
 	    tail_call_site_count++;
+	  if (optimize == 0 && !flag_var_tracking)
+	    {
+	      ...
+	    }
         }

Detect the case you are interested in (indirect calls), set up a few
vars and jump through down to the label creation (and arrange for that case
to understand that the current insn is not the note, but the call itself).
  
You'll need a small change on the final.c side, because
            if (!DECL_IGNORED_P (current_function_decl))
              debug_hooks->var_location (insn);
is called for calls before output_asm_insn, while you want to call it
after them (perhaps even after the unwind emit and final_postscan_insn),
so also replace
        if (rtx_call_insn *call_insn = dyn_cast <rtx_call_insn *> (insn))
with
	rtx_call_insn *call_insn = dyn_cast <rtx_call_insn *> (insn);
	if (call_insn)
and use that condition again for the var_location call.  I'd say
you can just leave call_arg_loc_note NULL in that case and use
              for (arg = (ca_loc->call_arg_loc_note
			  ? NOTE_VAR_LOCATION (ca_loc->call_arg_loc_note)
			  : NULL_RTX);
                   arg; arg = next_arg)
or so, no need to add any notes.
> +		  /* Emit a not only for calls that have a pattern that is not:

s/not/note/, but I hope this code is going away.

	Jakub
Pierre-Marie de Rodat Nov. 30, 2015, 11:08 a.m. UTC | #2
Hello Jakub,

On 11/24/2015 06:10 PM, Jakub Jelinek wrote:
> The new pass is IMNSHO completely useless and undesirable, both for compile
> time (another whole IL traversal) reasons and for the unnecessary creation
> of memory allocations.
> […]

Thank you for your detailed answer! This is just to say that I’m working 
on this matter: I hope I’ll be able to yield a patch implementing your 
proposal before the end of this week.
diff mbox

Patch

From 2a02ebc79b51693a341355a2301dc0f733591930 Mon Sep 17 00:00:00 2001
From: Pierre-Marie de Rodat <derodat@adacore.com>
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 <long, basic_block_def> bb_heap_t;
 typedef fibonacci_node <long, basic_block_def> 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