diff mbox

Handle many consecutive location notes more efficiently in dwarf2.

Message ID 20111030.215542.1009225198168800058.davem@davemloft.net
State New
Headers show

Commit Message

David Miller Oct. 31, 2011, 1:55 a.m. UTC
Tests such as limits-fndefn.c spend %97 of their time in
next_real_insn() when -g is on the command line.

It's the invocation from dwarf2out_var_location().  These test cases
are basically 100,000 consecutive var location notes, followed by a
real instruction.

This is similar to the reorg issue I dealt with yesterday, we
basically scan the entire function over and over again.

How I handle this here is if we see that the next insn is yet another
var location note we cache the next_real_insn() result.

Now limits-fndefn.c with "-O3 -g" takes about 20 seconds instead of
several minutes on my Niagara-T3 box.

Committed to trunk.

gcc/

	* dwarf2out.c (dwarf2out_var_location): When processing several
	consecutive location notes, cache the result of next_real_insn().

git-svn-id: svn+ssh://gcc.gnu.org/svn/gcc/trunk@180695 138bc75d-0d04-0410-961f-82ee72b054a4
---
 gcc/ChangeLog   |    5 +++++
 gcc/dwarf2out.c |   34 ++++++++++++++++++++++++++++++++--
 2 files changed, 37 insertions(+), 2 deletions(-)

Comments

Jakub Jelinek Oct. 31, 2011, 10:26 a.m. UTC | #1
On Sun, Oct 30, 2011 at 09:55:42PM -0400, David Miller wrote:
> --- a/gcc/dwarf2out.c
> +++ b/gcc/dwarf2out.c
> @@ -20149,7 +20151,35 @@ dwarf2out_var_location (rtx loc_note)
>    if (var_loc_p && !DECL_P (NOTE_VAR_LOCATION_DECL (loc_note)))
>      return;
>  
> -  next_real = next_real_insn (loc_note);
> +  /* Optimize processing a large consecutive sequence of location
> +     notes so we don't spend too much time in next_real_insn.  If the
> +     next insn is another location note, remember the next_real_insn
> +     calculation for next time.  */
> +  next_real = cached_next_real_insn;
> +  if (next_real)
> +    {
> +      if (expected_next_loc_note != loc_note)
> +	next_real = NULL_RTX;
> +    }
> +
> +  next_note = NEXT_INSN (loc_note);
> +  if (! next_note
> +      || INSN_DELETED_P (next_note)
> +      || GET_CODE (next_note) != NOTE
> +      || (NOTE_KIND (next_note) != NOTE_INSN_VAR_LOCATION

I think for next_note being NOTE_INSN_VAR_LOCATION you want to set
next_note to NULL_RTX if !DECL_P (NOTE_VAR_LOCATION_DECL (next_note)).

Otherwise you risk that the above
  if (var_loc_p && !DECL_P (NOTE_VAR_LOCATION_DECL (loc_note)))
    return;
will not clear the cache, you reach end of function and in the
next function when dwarf2out_var_location is called for the first time,
cached_next_real_insn will be non-NULL and if you have really bad luck
it will be called on insn that has the same address as
expected_next_loc_note (GC collection could happen in between).
Or alternatively you could remove the whole if (! !next_note ...) next_note = NULL_RTX;
stmt and move your cache to a global var and clear it when reaching end of
function (like e.g. last_var_location_insn is cleared in
dwarf2out_end_epilogue).

	Jakub
diff mbox

Patch

diff --git a/gcc/ChangeLog b/gcc/ChangeLog
index 26bb1a9..037138a 100644
--- a/gcc/ChangeLog
+++ b/gcc/ChangeLog
@@ -1,3 +1,8 @@ 
+2011-10-30  David S. Miller  <davem@davemloft.net>
+
+	* dwarf2out.c (dwarf2out_var_location): When processing several
+	consecutive location notes, cache the result of next_real_insn().
+
 2011-10-30  Uros Bizjak  <ubizjak@gmail.com>
 
 	* config/i386/i386.md (avx2_vec_dup<mode>): Macroize insn from
diff --git a/gcc/dwarf2out.c b/gcc/dwarf2out.c
index 8d5a9f0..478952f 100644
--- a/gcc/dwarf2out.c
+++ b/gcc/dwarf2out.c
@@ -20127,10 +20127,12 @@  dwarf2out_var_location (rtx loc_note)
 {
   char loclabel[MAX_ARTIFICIAL_LABEL_BYTES + 2];
   struct var_loc_node *newloc;
-  rtx next_real;
+  rtx next_real, next_note;
   static const char *last_label;
   static const char *last_postcall_label;
   static bool last_in_cold_section_p;
+  static rtx expected_next_loc_note;
+  static rtx cached_next_real_insn;
   tree decl;
   bool var_loc_p;
 
@@ -20149,7 +20151,35 @@  dwarf2out_var_location (rtx loc_note)
   if (var_loc_p && !DECL_P (NOTE_VAR_LOCATION_DECL (loc_note)))
     return;
 
-  next_real = next_real_insn (loc_note);
+  /* Optimize processing a large consecutive sequence of location
+     notes so we don't spend too much time in next_real_insn.  If the
+     next insn is another location note, remember the next_real_insn
+     calculation for next time.  */
+  next_real = cached_next_real_insn;
+  if (next_real)
+    {
+      if (expected_next_loc_note != loc_note)
+	next_real = NULL_RTX;
+    }
+
+  next_note = NEXT_INSN (loc_note);
+  if (! next_note
+      || INSN_DELETED_P (next_note)
+      || GET_CODE (next_note) != NOTE
+      || (NOTE_KIND (next_note) != NOTE_INSN_VAR_LOCATION
+	  && NOTE_KIND (next_note) != NOTE_INSN_CALL_ARG_LOCATION))
+    next_note = NULL_RTX;
+
+  if (! next_real)
+    next_real = next_real_insn (loc_note);
+
+  if (next_note)
+    {
+      expected_next_loc_note = next_note;
+      cached_next_real_insn = next_real;
+    }
+  else
+    cached_next_real_insn = NULL_RTX;
 
   /* If there are no instructions which would be affected by this note,
      don't do anything.  */