public inbox for gcc-patches@gcc.gnu.org
 help / color / mirror / Atom feed
* [PATCH] PR debug/47471 (set prologue_end in .debug_line)
@ 2011-03-30 19:39 Dodji Seketeli
  2011-03-31  6:22 ` Richard Henderson
  0 siblings, 1 reply; 6+ messages in thread
From: Dodji Seketeli @ 2011-03-30 19:39 UTC (permalink / raw)
  To: Richard Henderson; +Cc: Jan Kratochvil, GCC Patches

Hello,

This is about the line program emitted by the compiler into the
.debug_line section, without optimization.  In the example
accompanying the patch below, at the beginning of the function f, the
compiler emits two .loc asm directives that are identical.  The first
one is right before the .cfi_startproc that starts the prologue.  The
second one is before the instructions that copy the variable length
parameters into f's frame.  Both directives do locate instructions
that are in the prologue.

Unfortunately, GDB uses an heuristic that basically considers that the
first opcode of the line program that increments the line register
(even with an increment of zero) marks the end of the prologue.

Effectively, setting a breakpoint to the beginning of f (e.g, "break
f") won't work anymore when we emit this because GDB would then try to
set the breakpoint inside the prologue.

This patch does two things.

First, it avoids emitting two consecutive .loc that are identical.
Strictly speaking that should fix this issue in this particular case.

Second, it emits a '.loc <filenum> <linenum> 0 prologue_end' directive
on the first instruction that doesn't belong to the prologue (i.e,
when the end_prologue debug hook is called).  This sets the
prologue_end register in the .debug_line state machine to true.  After
discussing this with Jan (in CC), it appears that setting the
prologue_end register to true will help GDB to drop the somewhat
non-reliable heuristic it uses to detect the end of the prologue.

I have noticed that the end_prologue debug hook was being called, but
the dwarf back-end hasn't implemented it (on non-vms platforms).  Is
there a particular reason for not implementing this?  Also, I have
noticed that the patch causes the prologue_end directive to be emitted
even when we compile with optimizations.  I am not sure how right that
would be.

Tested on x86_64-unknown-linux-gnu against trunk.

-- 
		Dodji

From dc3dea429f1471540867a0b7e694a60494062ac0 Mon Sep 17 00:00:00 2001
From: Dodji Seketeli <dodji@redhat.com>
Date: Tue, 29 Mar 2011 16:56:20 +0200
Subject: [PATCH] PR debug/47471 (set prologue_end in .debug_line)

gcc/
	* dwarf2out.c (output_source_line_asm_info):  Split out of
	dwarf2out_source_line.  Add a new is_prologue_end parameter.
	Avoid emitting redundant consecutive .loc asm directives.
	(dwarf2out_source_line):  Use output_source_line_asm.
	(dwarf2out_end_prologue): New function.
	(dwarf2_debug_hooks->end_prologue): Set to dwarf2out_end_prologue.

gcc/testsuite/
	* gcc.dg/debug/dwarf2/line-prog-1.c: New test.
---
 gcc/dwarf2out.c |   95 +++++++++++++++++++++++++++++++++++++++++++++----------
 1 files changed, 78 insertions(+), 17 deletions(-)

diff --git a/gcc/dwarf2out.c b/gcc/dwarf2out.c
index efd30ea..6f8285c 100644
--- a/gcc/dwarf2out.c
+++ b/gcc/dwarf2out.c
@@ -94,6 +94,8 @@ along with GCC; see the file COPYING3.  If not see
 #include "tree-flow.h"
 #include "cfglayout.h"
 
+static void output_source_line_asm_info (unsigned int, const char *,
+					 int, bool, bool);
 static void dwarf2out_source_line (unsigned int, const char *, int, bool);
 static rtx last_var_location_insn;
 
@@ -465,6 +467,7 @@ static void output_call_frame_info (int);
 static void dwarf2out_note_section_used (void);
 static bool clobbers_queued_reg_save (const_rtx);
 static void dwarf2out_frame_debug_expr (rtx, const char *);
+static void dwarf2out_end_prologue (unsigned int, const char*);
 
 /* Support for complex CFA locations.  */
 static void output_cfa_loc (dw_cfi_ref, int);
@@ -4125,6 +4128,21 @@ dwarf2out_begin_prologue (unsigned int line ATTRIBUTE_UNUSED,
     }
 }
 
+/* Implementation of the gcc_debug_hooks::end_prologue hook.
+
+   If the underlying assembler supports it, emit a .loc asm directive
+   with a 'end_prologue' argument, effectively marking the point where
+   debugger should set a breakpoint when requested to set one on a
+   function.  */
+
+static void
+dwarf2out_end_prologue (unsigned int line, const char *filename)
+{
+  output_source_line_asm_info (line, filename, 0,
+			       /*is_stmt=*/true,
+			       /*is_prologue_end*/true);
+}
+
 /* Output a marker (i.e. a label) for the end of the generated code
    for a function prologue.  This gets called *after* the prologue code has
    been generated.  */
@@ -5767,7 +5785,7 @@ const struct gcc_debug_hooks dwarf2_debug_hooks =
   dwarf2out_vms_end_prologue,
   dwarf2out_vms_begin_epilogue,
 #else
-  debug_nothing_int_charstar,
+  dwarf2out_end_prologue,
   debug_nothing_int_charstar,
 #endif
   dwarf2out_end_epilogue,
@@ -22129,14 +22147,22 @@ dwarf2out_begin_function (tree fun)
 
 /* Output a label to mark the beginning of a source code line entry
    and record information relating to this source line, in
-   'line_info_table' for later output of the .debug_line section.  */
+   'line_info_table' for later output of the .debug_line section.
+
+   If the underlying assembler supports the .loc directive, use it
+   instead of emiting .debug_line state machine operations ourselves.
+
+   The arguments of the functions set their counterpart into the
+   .debug_line state machine registers.
+
+   This is a subroutine of dwarf2out_source_line and and
+   dwarf2out_end_prologue.  */
 
 static void
-dwarf2out_source_line (unsigned int line, const char *filename,
-                       int discriminator, bool is_stmt)
+output_source_line_asm_info (unsigned int line, const char *filename,
+			     int discriminator, bool is_stmt,
+			     bool is_prologue_end)
 {
-  static bool last_is_stmt = true;
-
   if (debug_info_level >= DINFO_LEVEL_NORMAL
       && line != 0)
     {
@@ -22151,19 +22177,42 @@ dwarf2out_source_line (unsigned int line, const char *filename,
 
       if (DWARF2_ASM_LINE_DEBUG_INFO)
 	{
-	  /* Emit the .loc directive understood by GNU as.  */
-	  fprintf (asm_out_file, "\t.loc %d %d 0", file_num, line);
-	  if (is_stmt != last_is_stmt)
+	  static int last_file_num = -1;
+	  static unsigned last_line = 0;
+	  static int last_discriminator = -1;
+	  static bool last_is_stmt = true;
+	  static int last_is_prologue_end = -1;
+
+	  if (last_file_num != file_num
+	      || last_line != line
+	      || last_is_stmt != is_stmt
+	      || last_discriminator != discriminator
+	      || last_is_prologue_end != is_prologue_end)
 	    {
-	      fprintf (asm_out_file, " is_stmt %d", is_stmt ? 1 : 0);
-	      last_is_stmt = is_stmt;
-	    }
-	  if (SUPPORTS_DISCRIMINATOR && discriminator != 0)
-	    fprintf (asm_out_file, " discriminator %d", discriminator);
-	  fputc ('\n', asm_out_file);
+	      /* Emit the .loc directive understood by GNU as.  */
+	      fprintf (asm_out_file, "\t.loc %d %d 0", file_num, line);
 
-	  /* Indicate that line number info exists.  */
-	  line_info_table_in_use++;
+	      if (is_stmt != last_is_stmt)
+		{
+		  fprintf (asm_out_file, " is_stmt %d", is_stmt ? 1 : 0);
+		  last_is_stmt = is_stmt;
+		}
+
+	      if (is_prologue_end)
+		fprintf (asm_out_file, " prologue_end");
+
+	      if (SUPPORTS_DISCRIMINATOR && discriminator != 0)
+		fprintf (asm_out_file, " discriminator %d", discriminator);
+	      fputc ('\n', asm_out_file);
+
+	      /* Indicate that line number info exists.  */
+	      line_info_table_in_use++;
+
+	      last_file_num = file_num;
+	      last_line = line;
+	      last_discriminator = discriminator;
+	      last_is_prologue_end = is_prologue_end;
+	    }
 	}
       else if (function_section (current_function_decl) != text_section)
 	{
@@ -22245,6 +22294,18 @@ dwarf2out_start_source_file (unsigned int lineno, const char *filename)
     }
 }
 
+/* Output a label to mark the beginning of a source code line entry
+   and record information relating to this source line, in
+   'line_info_table' for later output of the .debug_line section.  */
+
+static void
+dwarf2out_source_line (unsigned int line, const char *filename,
+                       int discriminator, bool is_stmt)
+{
+  output_source_line_asm_info (line, filename, discriminator,
+			       is_stmt, /*is_prolog_end=*/false);
+}
+
 /* Record the end of a source file.  */
 
 static void
-- 
1.7.3.4

^ permalink raw reply	[flat|nested] 6+ messages in thread

* Re: [PATCH] PR debug/47471 (set prologue_end in .debug_line)
  2011-03-30 19:39 [PATCH] PR debug/47471 (set prologue_end in .debug_line) Dodji Seketeli
@ 2011-03-31  6:22 ` Richard Henderson
  2011-03-31  9:25   ` Jan Kratochvil
  2011-03-31 14:48   ` Dodji Seketeli
  0 siblings, 2 replies; 6+ messages in thread
From: Richard Henderson @ 2011-03-31  6:22 UTC (permalink / raw)
  To: Dodji Seketeli; +Cc: Jan Kratochvil, GCC Patches

On 03/30/2011 11:19 AM, Dodji Seketeli wrote:
> First, it avoids emitting two consecutive .loc that are identical.
> Strictly speaking that should fix this issue in this particular case.

What's the compatibility strategy?  I.e. how does gdb tell that we're
not using the double-loc mechanism?  Does it scan the line ops and if
you see any prologue_end marks assume that double-loc is not in effect?

Are you actually going to be able to delete any code within gdb, due
to the need to interpret older debug info?

> I have noticed that the end_prologue debug hook was being called, but
> the dwarf back-end hasn't implemented it (on non-vms platforms).  Is
> there a particular reason for not implementing this?  Also, I have
> noticed that the patch causes the prologue_end directive to be emitted
> even when we compile with optimizations.  I am not sure how right that
> would be.

Well, the main problem with the existing end_prologue hook is the
definition of the "end of the prologue".

The hook you see is called *after* the last insn that was emitted
by gen_prologue.

I believe that the hook you want would be called *before* the first
insn that was originally emitted after NOTE_INSN_FUNCTION_BEG.
(Note that under certain conditions, the parameters need to be spilled
to their canonical locations, and other similar "prologue-like" stuff
happens after gen_prologue, and before the "real" function begins.)

Stop me now if I'm mistaken in this understanding of what gdb needs.

Without instruction scheduling, and without the need for parameter
spills, etc, these two definitions are (nearly) the same.  I.e. the
existing hook would likely work for -O0 -g, for many parameter lists.

On the other end, the definition the compiler uses for "begin the
epilogue" is also *before* the first insn that was emitted by
gen_epilogue.  And again I believe that what you want is *after*
the last insn that had been part of the main function body.

One possibility for noticing the debugger-definition of end of
prologue is simply to mark the first line number of the function.
None of the gen_prologue or parameter spill instructions will have
location information attached (I believe).  Thus the first insn 
that does generate a line number ought to be the first "active"
insn of the function.

Presumably one could do something similar at the ends of the
function; though that scan may be a tad more complicated.

Another problem is that we're not supporting these other features
without assembler support.  Which is silly.  I'm going to go ahead
and re-vamp how we're recording line number tables for direct output.
That should allow us to generate more-or-less equivalently capable
.debug_line output by hand.


r~

^ permalink raw reply	[flat|nested] 6+ messages in thread

* Re: [PATCH] PR debug/47471 (set prologue_end in .debug_line)
  2011-03-31  6:22 ` Richard Henderson
@ 2011-03-31  9:25   ` Jan Kratochvil
  2011-03-31 14:48   ` Dodji Seketeli
  1 sibling, 0 replies; 6+ messages in thread
From: Jan Kratochvil @ 2011-03-31  9:25 UTC (permalink / raw)
  To: Richard Henderson; +Cc: Dodji Seketeli, GCC Patches

On Thu, 31 Mar 2011 04:59:18 +0200, Richard Henderson wrote:
> On 03/30/2011 11:19 AM, Dodji Seketeli wrote:
> > First, it avoids emitting two consecutive .loc that are identical.
> > Strictly speaking that should fix this issue in this particular case.
> 
> What's the compatibility strategy?  I.e. how does gdb tell that we're
> not using the double-loc mechanism?  Does it scan the line ops and if
> you see any prologue_end marks assume that double-loc is not in effect?

Currently GDB ignores / has no support for DW_LNS_set_prologue_end.


> Are you actually going to be able to delete any code within gdb, due
> to the need to interpret older debug info?

No code is going to be deleted from GDB.


For -O2 -g code the prologue does not (will not) need to be known to GDB:
	[patch] Do not skip prologue for -O2 -g with GCC VTA Re: [patch] Fix for PR gdb/12573
	http://sourceware.org/ml/gdb-patches/2011-03/msg01129.html

For -O0 -g code the line number information may be good enough.  For
compatibility with older GDBs the line number tricks should remain in place
and in such case DW_LNS_set_prologue_end is redundant for -O0 -g.

I thought DW_LNS_set_prologue_end would be cleaner for -O0 -g but that may not
be required.


Thanks,
Jan

^ permalink raw reply	[flat|nested] 6+ messages in thread

* Re: [PATCH] PR debug/47471 (set prologue_end in .debug_line)
  2011-03-31  6:22 ` Richard Henderson
  2011-03-31  9:25   ` Jan Kratochvil
@ 2011-03-31 14:48   ` Dodji Seketeli
  2011-03-31 15:42     ` Richard Henderson
  1 sibling, 1 reply; 6+ messages in thread
From: Dodji Seketeli @ 2011-03-31 14:48 UTC (permalink / raw)
  To: Richard Henderson; +Cc: Jan Kratochvil, GCC Patches

Richard,

Thank you for the crystal clear explanation.  Now I understand why we
were not using the end_prologue debug hook before :-).

From what you say and from what Jan said, I think we could just keep the
part (of my earlier patch) that avoids emitting two consecutive
redundant .loc directives.  It seems to me that in the case of direct
output (i.e when we the underlying assembler doesn't support the .loc
directive) we already avoid the duplication.  And that avoidance fixes
the immediate issue GDB is facing, with -g -O0.

With -g -O>0, GDB doesn't have the issue as the DW_AT_location
attributes of the variable DIEs are locations that are valid in the
region of the prologue, so it doesn't need to know where the prologue
ends.  Just trusting DW_AT_location is enough.

I am currently testing the stripped down patch below.

Thanks.

-- 
		Dodji

From 87f97cc32bfac37264aa414c43d4ad47a9a35d72 Mon Sep 17 00:00:00 2001
From: Dodji Seketeli <dodji@redhat.com>
Date: Tue, 29 Mar 2011 16:56:20 +0200
Subject: [PATCH] PR debug/47471 (set prologue_end in .debug_line)

gcc/
	* dwarf2out.c (dwarf2out_source_line):
	Avoid emitting redundant consecutive .loc asm directives.

gcc/testsuite/

	* gcc.dg/debug/dwarf2/line-prog-1.c: New test.
---
 gcc/dwarf2out.c |   37 +++++++++++++++++++++++++------------
 1 files changed, 25 insertions(+), 12 deletions(-)

diff --git a/gcc/dwarf2out.c b/gcc/dwarf2out.c
index 91be9a4..7134315 100644
--- a/gcc/dwarf2out.c
+++ b/gcc/dwarf2out.c
@@ -22145,8 +22145,6 @@ static void
 dwarf2out_source_line (unsigned int line, const char *filename,
                        int discriminator, bool is_stmt)
 {
-  static bool last_is_stmt = true;
-
   if (debug_info_level >= DINFO_LEVEL_NORMAL
       && line != 0)
     {
@@ -22161,19 +22159,34 @@ dwarf2out_source_line (unsigned int line, const char *filename,
 
       if (DWARF2_ASM_LINE_DEBUG_INFO)
 	{
-	  /* Emit the .loc directive understood by GNU as.  */
-	  fprintf (asm_out_file, "\t.loc %d %d 0", file_num, line);
-	  if (is_stmt != last_is_stmt)
+	  static bool last_is_stmt = true;
+	  static int last_file_num = -1;
+	  static unsigned last_line = 0;
+	  static int last_discriminator = -1;
+
+	  if (last_file_num != file_num
+	      || last_line != line
+	      || last_is_stmt != is_stmt
+	      || last_discriminator != discriminator)
 	    {
-	      fprintf (asm_out_file, " is_stmt %d", is_stmt ? 1 : 0);
+	      /* Emit the .loc directive understood by GNU as.  */
+	      fprintf (asm_out_file, "\t.loc %d %d 0", file_num, line);
+
+	      if (is_stmt != last_is_stmt)
+		fprintf (asm_out_file, " is_stmt %d", is_stmt ? 1 : 0);
+
+	      if (SUPPORTS_DISCRIMINATOR && discriminator != 0)
+		fprintf (asm_out_file, " discriminator %d", discriminator);
+	      fputc ('\n', asm_out_file);
+
+	      /* Indicate that line number info exists.  */
+	      line_info_table_in_use++;
+
+	      last_file_num = file_num;
+	      last_line = line;
+	      last_discriminator = discriminator;
 	      last_is_stmt = is_stmt;
 	    }
-	  if (SUPPORTS_DISCRIMINATOR && discriminator != 0)
-	    fprintf (asm_out_file, " discriminator %d", discriminator);
-	  fputc ('\n', asm_out_file);
-
-	  /* Indicate that line number info exists.  */
-	  line_info_table_in_use++;
 	}
       else if (function_section (current_function_decl) != text_section)
 	{
-- 
1.7.3.4

^ permalink raw reply	[flat|nested] 6+ messages in thread

* Re: [PATCH] PR debug/47471 (set prologue_end in .debug_line)
  2011-03-31 14:48   ` Dodji Seketeli
@ 2011-03-31 15:42     ` Richard Henderson
  2011-04-01  2:57       ` Enhance non-assembler .debug_line output Richard Henderson
  0 siblings, 1 reply; 6+ messages in thread
From: Richard Henderson @ 2011-03-31 15:42 UTC (permalink / raw)
  To: Dodji Seketeli; +Cc: Jan Kratochvil, GCC Patches

On 03/31/2011 07:35 AM, Dodji Seketeli wrote:
> redundant .loc directives.  It seems to me that in the case of direct
> output (i.e when we the underlying assembler doesn't support the .loc
> directive) we already avoid the duplication.  And that avoidance fixes
> the immediate issue GDB is facing, with -g -O0.

There's no avoidance with direct output either.  See the #if 0 bits
inside output_line_info itself.

#if 0
      /* Don't emit anything for redundant notes.  */
      if (line_info->dw_line_num == current_line
          && line_info->dw_file_num == current_file
          && line_info->function == function)
        goto cont;
#endif

> With -g -O>0, GDB doesn't have the issue as the DW_AT_location
> attributes of the variable DIEs are locations that are valid in the
> region of the prologue, so it doesn't need to know where the prologue
> ends.  Just trusting DW_AT_location is enough.

Ah, I see.  And I can see how having end_prologue might help there.
Well, let's see if we can clean things up here then.

As for your patch itself, you're not checking to see if you're outputting
to the same section, which could cause line info to go missing at the
beginning of a different section.

That said, the patch I'm working on will do this elimination in one place
for both direct output and assembler output, and be mindful of sections.


r~

^ permalink raw reply	[flat|nested] 6+ messages in thread

* Enhance non-assembler .debug_line output
  2011-03-31 15:42     ` Richard Henderson
@ 2011-04-01  2:57       ` Richard Henderson
  0 siblings, 0 replies; 6+ messages in thread
From: Richard Henderson @ 2011-04-01  2:57 UTC (permalink / raw)
  To: GCC Patches; +Cc: Dodji Seketeli, Jan Kratochvil

[-- Attachment #1: Type: text/plain, Size: 1243 bytes --]

On 03/31/2011 08:37 AM, Richard Henderson wrote:
> That said, the patch I'm working on will do this elimination in one place
> for both direct output and assembler output, and be mindful of sections.

Ok, well, I haven't actually enabled the elimination.  It's if 0'd out
exactly like in current sources.  But that's easy to change in one place.

What this patch does is enable the generation of all dwarf line number
information.  Which includes the is_stmt and discriminator stuff that
we already generate via the explicit assembler directives.  Previously
all we could emit were the raw line numbers.

I believe that all of this code could be cleaned up by moving all of
the begin-section/end-section label manipulation into the varasm section
handling directly.  At present, I have access to an end-section label
for .text and .text.unlikely, but not for .text.hot.  This means we
emit too many DW_LNS_end_sequences.  This is not wrong, but perhaps a
bit wasteful.  Plus all the code that emits these begin/end labels is
scattered all over the place.

Tested on x86_64-linux, with a hack in place to force the use of the
non-assembler paths, and building with profiledbootstrap in order to
force the use of sections other than .text.


r~

[-- Attachment #2: z --]
[-- Type: text/plain, Size: 33596 bytes --]

	* dwarf2out.c (dw_separate_line_info_ref): Remove.
	(dw_separate_line_info_entry): Remove.
	(enum dw_line_info_opcode): New.
	(dw_line_info_entry): Use it.
	(dw_line_info_table, dw_line_info_table_p): New.
	(DWARF_LINE_OPCODE_BASE): Include dwarf3 opcodes.
	(line_info_table, line_info_label_num): Remove.
	(line_info_table_in_use): Remove.
	(separate_line_info_table): Remove.
	(separate_line_info_table_allocated): Remove.
	(separate_line_info_table_in_use): Remove.
	(LINE_INFO_TABLE_INCREMENT): Remove.
	(line_info_label_num): New.
	(cur_line_info_table): New.
	(text_section_line_info, cold_text_section_line_info): New.
	(separate_line_info): New.
	(SEPARATE_LINE_CODE_LABEL): Remove.
	(print_dwarf_line_table): Remove.
	(debug_dwarf): Don't dump it.
	(output_one_line_info_table): New.
	(output_line_info): Use it.
	(new_line_info_table): New.
	(set_cur_line_info_table): New.
	(dwarf2out_switch_text_section): Use it.
	(dwarf2out_begin_function): Likewise.
	(push_dw_line_info_entry): New.
	(dwarf2out_source_line): Rewrite for new line info tables.
	(dwarf2out_init): Remove dead initailizations.


diff --git a/gcc/dwarf2out.c b/gcc/dwarf2out.c
index 91be9a4..4b7afe4 100644
--- a/gcc/dwarf2out.c
+++ b/gcc/dwarf2out.c
@@ -4242,6 +4242,7 @@ dwarf2out_note_section_used (void)
 }
 
 static void var_location_switch_text_section (void);
+static void set_cur_line_info_table (section *);
 
 void
 dwarf2out_switch_text_section (void)
@@ -4298,6 +4299,8 @@ dwarf2out_switch_text_section (void)
       cfi = cfi->dw_cfi_next;
   fde->dw_fde_switch_cfi = cfi;
   var_location_switch_text_section ();
+
+  set_cur_line_info_table (sect);
 }
 \f
 /* And now, the subset of the debugging information support code necessary
@@ -5819,31 +5822,70 @@ typedef long int dw_offset;
 
 typedef struct dw_attr_struct *dw_attr_ref;
 typedef struct dw_line_info_struct *dw_line_info_ref;
-typedef struct dw_separate_line_info_struct *dw_separate_line_info_ref;
 typedef struct pubname_struct *pubname_ref;
 typedef struct dw_ranges_struct *dw_ranges_ref;
 typedef struct dw_ranges_by_label_struct *dw_ranges_by_label_ref;
 typedef struct comdat_type_struct *comdat_type_node_ref;
 
-/* Each entry in the line_info_table maintains the file and
-   line number associated with the label generated for that
-   entry.  The label gives the PC value associated with
-   the line number entry.  */
+/* The entries in the line_info table more-or-less mirror the opcodes
+   that are used in the real dwarf line table.  Arrays of these entries
+   are collected per section when DWARF2_ASM_LINE_DEBUG_INFO is not
+   supported.  */
+
+enum dw_line_info_opcode {
+  /* Emit DW_LNE_set_address; the operand is the label index.  */
+  LI_set_address,
+
+  /* Emit a row to the matrix with the given line.  This may be done
+     via any combination of DW_LNS_copy, DW_LNS_advance_line, and
+     special opcodes.  */
+  LI_set_line,
+
+  /* Emit a DW_LNS_set_file.  */
+  LI_set_file,
+
+  /* Emit a DW_LNS_set_column.  */
+  LI_set_column,
+
+  /* Emit a DW_LNS_negate_stmt; the operand is ignored.  */
+  LI_negate_stmt,
+
+  /* Emit a DW_LNS_set_prologue_end/epilogue_begin; the operand is ignored.  */
+  LI_set_prologue_end,
+  LI_set_epilogue_begin,
+
+  /* Emit a DW_LNE_set_discriminator.  */
+  LI_set_discriminator
+};
 
 typedef struct GTY(()) dw_line_info_struct {
-  unsigned long dw_file_num;
-  unsigned long dw_line_num;
-}
-dw_line_info_entry;
+  enum dw_line_info_opcode opcode;
+  unsigned int val;
+} dw_line_info_entry;
 
-/* Line information for functions in separate sections; each one gets its
-   own sequence.  */
-typedef struct GTY(()) dw_separate_line_info_struct {
-  unsigned long dw_file_num;
-  unsigned long dw_line_num;
-  unsigned long function;
-}
-dw_separate_line_info_entry;
+DEF_VEC_O(dw_line_info_entry);
+DEF_VEC_ALLOC_O(dw_line_info_entry, gc);
+
+typedef struct GTY(()) dw_line_info_table_struct {
+  /* The label that marks the end of this section.  */
+  const char *end_label;
+
+  /* The values for the last row of the matrix, as collected in the table.
+     These are used to minimize the changes to the next row.  */
+  unsigned int file_num;
+  unsigned int line_num;
+  unsigned int column_num;
+  int discrim_num;
+  bool is_stmt;
+  bool in_use;
+
+  VEC(dw_line_info_entry, gc) *entries;
+} dw_line_info_table;
+
+typedef dw_line_info_table *dw_line_info_table_p;
+
+DEF_VEC_P(dw_line_info_table_p);
+DEF_VEC_ALLOC_P(dw_line_info_table_p, gc);
 
 /* Each DIE attribute has a field specifying the attribute kind,
    a link to the next attribute in the chain, and an attribute value.
@@ -6021,7 +6063,7 @@ skeleton_chain_node;
 #define DWARF_LINE_BASE  -10
 
 /* First special line opcode - leave room for the standard opcodes.  */
-#define DWARF_LINE_OPCODE_BASE  10
+#define DWARF_LINE_OPCODE_BASE  ((int)DW_LNS_set_isa + 1)
 
 /* Range of line offsets in a special line info. opcode.  */
 #define DWARF_LINE_RANGE  (254-DWARF_LINE_OPCODE_BASE+1)
@@ -6166,31 +6208,20 @@ static GTY(()) unsigned abbrev_die_table_in_use;
    abbrev_die_table.  */
 #define ABBREV_DIE_TABLE_INCREMENT 256
 
-/* A pointer to the base of a table that contains line information
-   for each source code line in .text in the compilation unit.  */
-static GTY((length ("line_info_table_allocated")))
-     dw_line_info_ref line_info_table;
+/* A global counter for generating labels for line number data.  */
+static unsigned int line_info_label_num;
 
-/* Number of elements currently allocated for line_info_table.  */
-static GTY(()) unsigned line_info_table_allocated;
+/* The current table to which we should emit line number information
+   for the current function.  This will be set up at the beginning of
+   assembly for the function.  */
+static dw_line_info_table *cur_line_info_table;
 
-/* Number of elements in line_info_table currently in use.  */
-static GTY(()) unsigned line_info_table_in_use;
+/* The two default tables of line number info.  */
+static GTY(()) dw_line_info_table *text_section_line_info;
+static GTY(()) dw_line_info_table *cold_text_section_line_info;
 
-/* A pointer to the base of a table that contains line information
-   for each source code line outside of .text in the compilation unit.  */
-static GTY ((length ("separate_line_info_table_allocated")))
-     dw_separate_line_info_ref separate_line_info_table;
-
-/* Number of elements currently allocated for separate_line_info_table.  */
-static GTY(()) unsigned separate_line_info_table_allocated;
-
-/* Number of elements in separate_line_info_table currently in use.  */
-static GTY(()) unsigned separate_line_info_table_in_use;
-
-/* Size (in elements) of increments by which we may expand the
-   line_info_table.  */
-#define LINE_INFO_TABLE_INCREMENT 1024
+/* The set of all non-default tables of line number info.  */
+static GTY(()) VEC (dw_line_info_table_p, gc) *separate_line_info;
 
 /* A flag to tell pubnames/types export if there is an info section to
    refer to.  */
@@ -6343,7 +6374,6 @@ static void equate_decl_number_to_die (tree, dw_die_ref);
 static struct var_loc_node *add_var_loc_to_decl (tree, rtx, const char *);
 static void print_spaces (FILE *);
 static void print_die (dw_die_ref, FILE *);
-static void print_dwarf_line_table (FILE *);
 static dw_die_ref push_new_compile_unit (dw_die_ref, dw_die_ref);
 static dw_die_ref pop_compile_unit (dw_die_ref);
 static void loc_checksum (dw_loc_descr_ref, struct md5_ctx *);
@@ -6421,6 +6451,7 @@ static unsigned int add_ranges (const_tree);
 static void add_ranges_by_labels (dw_die_ref, const char *, const char *,
 				  bool *);
 static void output_ranges (void);
+static dw_line_info_table *new_line_info_table (void);
 static void output_line_info (void);
 static void output_file_names (void);
 static dw_die_ref base_type_die (tree);
@@ -6662,9 +6693,6 @@ static char ranges_section_label[2 * MAX_ARTIFICIAL_LABEL_BYTES];
 #ifndef LINE_CODE_LABEL
 #define LINE_CODE_LABEL		"LM"
 #endif
-#ifndef SEPARATE_LINE_CODE_LABEL
-#define SEPARATE_LINE_CODE_LABEL	"LSM"
-#endif
 
 \f
 /* Return the root of the DIE's built for the current compilation unit.  */
@@ -8682,27 +8710,6 @@ print_die (dw_die_ref die, FILE *outfile)
     fprintf (outfile, "\n");
 }
 
-/* Print the contents of the source code line number correspondence table.
-   This routine is a debugging aid only.  */
-
-static void
-print_dwarf_line_table (FILE *outfile)
-{
-  unsigned i;
-  dw_line_info_ref line_info;
-
-  fprintf (outfile, "\n\nDWARF source line information\n");
-  for (i = 1; i < line_info_table_in_use; i++)
-    {
-      line_info = &line_info_table[i];
-      fprintf (outfile, "%5d: %4ld %6ld\n", i,
-	       line_info->dw_file_num,
-	       line_info->dw_line_num);
-    }
-
-  fprintf (outfile, "\n\n");
-}
-
 /* Print the information collected for a given DIE.  */
 
 DEBUG_FUNCTION void
@@ -8719,8 +8726,6 @@ debug_dwarf (void)
 {
   print_indent = 0;
   print_die (comp_unit_die (), stderr);
-  if (! DWARF2_ASM_LINE_DEBUG_INFO)
-    print_dwarf_line_table (stderr);
 }
 \f
 /* Start a new compilation unit DIE for an include file.  OLD_UNIT is the CU
@@ -12289,6 +12294,117 @@ output_file_names (void)
 }
 
 
+/* Output one line number table into the .debug_line section.  */
+
+static void
+output_one_line_info_table (dw_line_info_table *table)
+{
+  char line_label[MAX_ARTIFICIAL_LABEL_BYTES];
+  unsigned int current_line = 1;
+  bool current_is_stmt = DWARF_LINE_DEFAULT_IS_STMT_START;
+  dw_line_info_entry *ent;
+  size_t i;
+
+  FOR_EACH_VEC_ELT (dw_line_info_entry, table->entries, i, ent)
+    {
+      switch (ent->opcode)
+	{
+	case LI_set_address:
+	  /* ??? Unfortunately, we have little choice here currently, and
+	     must always use the most general form.  GCC does not know the
+	     address delta itself, so we can't use DW_LNS_advance_pc.  Many
+	     ports do have length attributes which will give an upper bound
+	     on the address range.  We could perhaps use length attributes
+	     to determine when it is safe to use DW_LNS_fixed_advance_pc.  */
+	  ASM_GENERATE_INTERNAL_LABEL (line_label, LINE_CODE_LABEL, ent->val);
+
+	  /* This can handle any delta.  This takes
+	     4+DWARF2_ADDR_SIZE bytes.  */
+	  dw2_asm_output_data (1, 0, "set address %s", line_label);
+	  dw2_asm_output_data_uleb128 (1 + DWARF2_ADDR_SIZE, NULL);
+	  dw2_asm_output_data (1, DW_LNE_set_address, NULL);
+	  dw2_asm_output_addr (DWARF2_ADDR_SIZE, line_label, NULL);
+	  break;
+
+	case LI_set_line:
+	  if (ent->val == current_line)
+	    {
+	      /* We still need to start a new row, so output a copy insn.  */
+	      dw2_asm_output_data (1, DW_LNS_copy,
+				   "copy line %u", current_line);
+	    }
+	  else
+	    {
+	      int line_offset = ent->val - current_line;
+	      int line_delta = line_offset - DWARF_LINE_BASE;
+
+	      current_line = ent->val;
+	      if (line_delta >= 0 && line_delta < (DWARF_LINE_RANGE - 1))
+		{
+		  /* This can handle deltas from -10 to 234, using the current
+		     definitions of DWARF_LINE_BASE and DWARF_LINE_RANGE.
+		     This takes 1 byte.  */
+		  dw2_asm_output_data (1, DWARF_LINE_OPCODE_BASE + line_delta,
+				       "line %u", current_line);
+		}
+	      else
+		{
+		  /* This can handle any delta.  This takes at least 4 bytes,
+		     depending on the value being encoded.  */
+		  dw2_asm_output_data (1, DW_LNS_advance_line,
+				       "advance to line %u", current_line);
+		  dw2_asm_output_data_sleb128 (line_offset, NULL);
+		  dw2_asm_output_data (1, DW_LNS_copy, NULL);
+		}
+	    }
+	  break;
+
+	case LI_set_file:
+	  dw2_asm_output_data (1, DW_LNS_set_file, "set file %u", ent->val);
+	  dw2_asm_output_data_uleb128 (ent->val, "%u", ent->val);
+	  break;
+
+	case LI_set_column:
+	  dw2_asm_output_data (1, DW_LNS_set_column, "column %u", ent->val);
+	  dw2_asm_output_data_uleb128 (ent->val, "%u", ent->val);
+	  break;
+
+	case LI_negate_stmt:
+	  current_is_stmt = !current_is_stmt;
+	  dw2_asm_output_data (1, DW_LNS_negate_stmt,
+			       "is_stmt %d", current_is_stmt);
+	  break;
+
+	case LI_set_prologue_end:
+	  dw2_asm_output_data (1, DW_LNS_set_prologue_end,
+			       "set prologue end");
+	  break;
+	  
+	case LI_set_epilogue_begin:
+	  dw2_asm_output_data (1, DW_LNS_set_epilogue_begin,
+			       "set epilogue begin");
+	  break;
+
+	case LI_set_discriminator:
+	  dw2_asm_output_data (1, 0, "discriminator %u", ent->val);
+	  dw2_asm_output_data_uleb128 (1 + size_of_uleb128 (ent->val), NULL);
+	  dw2_asm_output_data (1, DW_LNE_set_discriminator, NULL);
+	  dw2_asm_output_data_uleb128 (ent->val, NULL);
+	  break;
+	}
+    }
+
+  /* Emit debug info for the address of the end of the table.  */
+  dw2_asm_output_data (1, 0, "set address %s", table->end_label);
+  dw2_asm_output_data_uleb128 (1 + DWARF2_ADDR_SIZE, NULL);
+  dw2_asm_output_data (1, DW_LNE_set_address, NULL);
+  dw2_asm_output_addr (DWARF2_ADDR_SIZE, table->end_label, NULL);
+
+  dw2_asm_output_data (1, 0, "end sequence");
+  dw2_asm_output_data_uleb128 (1, NULL);
+  dw2_asm_output_data (1, DW_LNE_end_sequence, NULL);
+}
+
 /* Output the source line number correspondence information.  This
    information goes into the .debug_line section.  */
 
@@ -12296,17 +12412,8 @@ static void
 output_line_info (void)
 {
   char l1[20], l2[20], p1[20], p2[20];
-  char line_label[MAX_ARTIFICIAL_LABEL_BYTES];
-  char prev_line_label[MAX_ARTIFICIAL_LABEL_BYTES];
-  unsigned opc;
-  unsigned n_op_args;
-  unsigned long lt_index;
-  unsigned long current_line;
-  long line_offset;
-  long line_delta;
-  unsigned long current_file;
-  unsigned long function;
   int ver = dwarf_version;
+  int opc;
 
   ASM_GENERATE_INTERNAL_LABEL (l1, LINE_NUMBER_BEGIN_LABEL, 0);
   ASM_GENERATE_INTERNAL_LABEL (l2, LINE_NUMBER_END_LABEL, 0);
@@ -12324,16 +12431,15 @@ output_line_info (void)
   dw2_asm_output_delta (DWARF_OFFSET_SIZE, p2, p1, "Prolog Length");
   ASM_OUTPUT_LABEL (asm_out_file, p1);
 
-  /* Define the architecture-dependent minimum instruction length (in
-   bytes).  In this implementation of DWARF, this field is used for
-   information purposes only.  Since GCC generates assembly language,
-   we have no a priori knowledge of how many instruction bytes are
-   generated for each source line, and therefore can use only the
-   DW_LNE_set_address and DW_LNS_fixed_advance_pc line information
-   commands.  Accordingly, we fix this as `1', which is "correct
-   enough" for all architectures, and don't let the target override.  */
-  dw2_asm_output_data (1, 1,
-		       "Minimum Instruction Length");
+  /* Define the architecture-dependent minimum instruction length (in bytes).
+     In this implementation of DWARF, this field is used for information
+     purposes only.  Since GCC generates assembly language, we have no
+     a priori knowledge of how many instruction bytes are generated for each
+     source line, and therefore can use only the DW_LNE_set_address and
+     DW_LNS_fixed_advance_pc line information commands.  Accordingly, we fix
+     this as '1', which is "correct enough" for all architectures,
+     and don't let the target override.  */
+  dw2_asm_output_data (1, 1, "Minimum Instruction Length");
 
   if (ver >= 4)
     dw2_asm_output_data (1, DWARF_LINE_DEFAULT_MAX_OPS_PER_INSN,
@@ -12349,6 +12455,7 @@ output_line_info (void)
 
   for (opc = 1; opc < DWARF_LINE_OPCODE_BASE; opc++)
     {
+      int n_op_args;
       switch (opc)
 	{
 	case DW_LNS_advance_pc:
@@ -12356,6 +12463,7 @@ output_line_info (void)
 	case DW_LNS_set_file:
 	case DW_LNS_set_column:
 	case DW_LNS_fixed_advance_pc:
+	case DW_LNS_set_isa:
 	  n_op_args = 1;
 	  break;
 	default:
@@ -12371,236 +12479,19 @@ output_line_info (void)
   output_file_names ();
   ASM_OUTPUT_LABEL (asm_out_file, p2);
 
-  /* We used to set the address register to the first location in the text
-     section here, but that didn't accomplish anything since we already
-     have a line note for the opening brace of the first function.  */
-
-  /* Generate the line number to PC correspondence table, encoded as
-     a series of state machine operations.  */
-  current_file = 1;
-  current_line = 1;
-
-  if (cfun && in_cold_section_p)
-    strcpy (prev_line_label, crtl->subsections.cold_section_label);
-  else
-    strcpy (prev_line_label, text_section_label);
-  for (lt_index = 1; lt_index < line_info_table_in_use; ++lt_index)
-    {
-      dw_line_info_ref line_info = &line_info_table[lt_index];
-
-#if 0
-      /* Disable this optimization for now; GDB wants to see two line notes
-	 at the beginning of a function so it can find the end of the
-	 prologue.  */
-
-      /* Don't emit anything for redundant notes.  Just updating the
-	 address doesn't accomplish anything, because we already assume
-	 that anything after the last address is this line.  */
-      if (line_info->dw_line_num == current_line
-	  && line_info->dw_file_num == current_file)
-	continue;
-#endif
-
-      /* Emit debug info for the address of the current line.
-
-	 Unfortunately, we have little choice here currently, and must always
-	 use the most general form.  GCC does not know the address delta
-	 itself, so we can't use DW_LNS_advance_pc.  Many ports do have length
-	 attributes which will give an upper bound on the address range.  We
-	 could perhaps use length attributes to determine when it is safe to
-	 use DW_LNS_fixed_advance_pc.  */
+  if (text_section_line_info && text_section_line_info->in_use)
+    output_one_line_info_table (text_section_line_info);
+  if (cold_text_section_line_info && cold_text_section_line_info->in_use)
+    output_one_line_info_table (cold_text_section_line_info);
 
-      ASM_GENERATE_INTERNAL_LABEL (line_label, LINE_CODE_LABEL, lt_index);
-      if (0)
-	{
-	  /* This can handle deltas up to 0xffff.  This takes 3 bytes.  */
-	  dw2_asm_output_data (1, DW_LNS_fixed_advance_pc,
-			       "DW_LNS_fixed_advance_pc");
-	  dw2_asm_output_delta (2, line_label, prev_line_label, NULL);
-	}
-      else
-	{
-	  /* This can handle any delta.  This takes
-	     4+DWARF2_ADDR_SIZE bytes.  */
-	  dw2_asm_output_data (1, 0, "DW_LNE_set_address");
-	  dw2_asm_output_data_uleb128 (1 + DWARF2_ADDR_SIZE, NULL);
-	  dw2_asm_output_data (1, DW_LNE_set_address, NULL);
-	  dw2_asm_output_addr (DWARF2_ADDR_SIZE, line_label, NULL);
-	}
-
-      strcpy (prev_line_label, line_label);
-
-      /* Emit debug info for the source file of the current line, if
-	 different from the previous line.  */
-      if (line_info->dw_file_num != current_file)
-	{
-	  current_file = line_info->dw_file_num;
-	  dw2_asm_output_data (1, DW_LNS_set_file, "DW_LNS_set_file");
-	  dw2_asm_output_data_uleb128 (current_file, "%lu", current_file);
-	}
-
-      /* Emit debug info for the current line number, choosing the encoding
-	 that uses the least amount of space.  */
-      if (line_info->dw_line_num != current_line)
-	{
-	  line_offset = line_info->dw_line_num - current_line;
-	  line_delta = line_offset - DWARF_LINE_BASE;
-	  current_line = line_info->dw_line_num;
-	  if (line_delta >= 0 && line_delta < (DWARF_LINE_RANGE - 1))
-	    /* This can handle deltas from -10 to 234, using the current
-	       definitions of DWARF_LINE_BASE and DWARF_LINE_RANGE.  This
-	       takes 1 byte.  */
-	    dw2_asm_output_data (1, DWARF_LINE_OPCODE_BASE + line_delta,
-				 "line %lu", current_line);
-	  else
-	    {
-	      /* This can handle any delta.  This takes at least 4 bytes,
-		 depending on the value being encoded.  */
-	      dw2_asm_output_data (1, DW_LNS_advance_line,
-				   "advance to line %lu", current_line);
-	      dw2_asm_output_data_sleb128 (line_offset, NULL);
-	      dw2_asm_output_data (1, DW_LNS_copy, "DW_LNS_copy");
-	    }
-	}
-      else
-	/* We still need to start a new row, so output a copy insn.  */
-	dw2_asm_output_data (1, DW_LNS_copy, "DW_LNS_copy");
-    }
-
-  /* Emit debug info for the address of the end of the function.  */
-  if (0)
+  if (separate_line_info)
     {
-      dw2_asm_output_data (1, DW_LNS_fixed_advance_pc,
-			   "DW_LNS_fixed_advance_pc");
-      dw2_asm_output_delta (2, text_end_label, prev_line_label, NULL);
-    }
-  else
-    {
-      dw2_asm_output_data (1, 0, "DW_LNE_set_address");
-      dw2_asm_output_data_uleb128 (1 + DWARF2_ADDR_SIZE, NULL);
-      dw2_asm_output_data (1, DW_LNE_set_address, NULL);
-      dw2_asm_output_addr (DWARF2_ADDR_SIZE, text_end_label, NULL);
-    }
-
-  dw2_asm_output_data (1, 0, "DW_LNE_end_sequence");
-  dw2_asm_output_data_uleb128 (1, NULL);
-  dw2_asm_output_data (1, DW_LNE_end_sequence, NULL);
-
-  function = 0;
-  current_file = 1;
-  current_line = 1;
-  for (lt_index = 0; lt_index < separate_line_info_table_in_use;)
-    {
-      dw_separate_line_info_ref line_info
-	= &separate_line_info_table[lt_index];
-
-#if 0
-      /* Don't emit anything for redundant notes.  */
-      if (line_info->dw_line_num == current_line
-	  && line_info->dw_file_num == current_file
-	  && line_info->function == function)
-	goto cont;
-#endif
-
-      /* Emit debug info for the address of the current line.  If this is
-	 a new function, or the first line of a function, then we need
-	 to handle it differently.  */
-      ASM_GENERATE_INTERNAL_LABEL (line_label, SEPARATE_LINE_CODE_LABEL,
-				   lt_index);
-      if (function != line_info->function)
-	{
-	  function = line_info->function;
-
-	  /* Set the address register to the first line in the function.  */
-	  dw2_asm_output_data (1, 0, "DW_LNE_set_address");
-	  dw2_asm_output_data_uleb128 (1 + DWARF2_ADDR_SIZE, NULL);
-	  dw2_asm_output_data (1, DW_LNE_set_address, NULL);
-	  dw2_asm_output_addr (DWARF2_ADDR_SIZE, line_label, NULL);
-	}
-      else
-	{
-	  /* ??? See the DW_LNS_advance_pc comment above.  */
-	  if (0)
-	    {
-	      dw2_asm_output_data (1, DW_LNS_fixed_advance_pc,
-				   "DW_LNS_fixed_advance_pc");
-	      dw2_asm_output_delta (2, line_label, prev_line_label, NULL);
-	    }
-	  else
-	    {
-	      dw2_asm_output_data (1, 0, "DW_LNE_set_address");
-	      dw2_asm_output_data_uleb128 (1 + DWARF2_ADDR_SIZE, NULL);
-	      dw2_asm_output_data (1, DW_LNE_set_address, NULL);
-	      dw2_asm_output_addr (DWARF2_ADDR_SIZE, line_label, NULL);
-	    }
-	}
-
-      strcpy (prev_line_label, line_label);
-
-      /* Emit debug info for the source file of the current line, if
-	 different from the previous line.  */
-      if (line_info->dw_file_num != current_file)
-	{
-	  current_file = line_info->dw_file_num;
-	  dw2_asm_output_data (1, DW_LNS_set_file, "DW_LNS_set_file");
-	  dw2_asm_output_data_uleb128 (current_file, "%lu", current_file);
-	}
-
-      /* Emit debug info for the current line number, choosing the encoding
-	 that uses the least amount of space.  */
-      if (line_info->dw_line_num != current_line)
-	{
-	  line_offset = line_info->dw_line_num - current_line;
-	  line_delta = line_offset - DWARF_LINE_BASE;
-	  current_line = line_info->dw_line_num;
-	  if (line_delta >= 0 && line_delta < (DWARF_LINE_RANGE - 1))
-	    dw2_asm_output_data (1, DWARF_LINE_OPCODE_BASE + line_delta,
-				 "line %lu", current_line);
-	  else
-	    {
-	      dw2_asm_output_data (1, DW_LNS_advance_line,
-				   "advance to line %lu", current_line);
-	      dw2_asm_output_data_sleb128 (line_offset, NULL);
-	      dw2_asm_output_data (1, DW_LNS_copy, "DW_LNS_copy");
-	    }
-	}
-      else
-	dw2_asm_output_data (1, DW_LNS_copy, "DW_LNS_copy");
-
-#if 0
-    cont:
-#endif
-
-      lt_index++;
-
-      /* If we're done with a function, end its sequence.  */
-      if (lt_index == separate_line_info_table_in_use
-	  || separate_line_info_table[lt_index].function != function)
-	{
-	  current_file = 1;
-	  current_line = 1;
-
-	  /* Emit debug info for the address of the end of the function.  */
-	  ASM_GENERATE_INTERNAL_LABEL (line_label, FUNC_END_LABEL, function);
-	  if (0)
-	    {
-	      dw2_asm_output_data (1, DW_LNS_fixed_advance_pc,
-				   "DW_LNS_fixed_advance_pc");
-	      dw2_asm_output_delta (2, line_label, prev_line_label, NULL);
-	    }
-	  else
-	    {
-	      dw2_asm_output_data (1, 0, "DW_LNE_set_address");
-	      dw2_asm_output_data_uleb128 (1 + DWARF2_ADDR_SIZE, NULL);
-	      dw2_asm_output_data (1, DW_LNE_set_address, NULL);
-	      dw2_asm_output_addr (DWARF2_ADDR_SIZE, line_label, NULL);
-	    }
+      dw_line_info_table *table;
+      size_t i;
 
-	  /* Output the marker for the end of this sequence.  */
-	  dw2_asm_output_data (1, 0, "DW_LNE_end_sequence");
-	  dw2_asm_output_data_uleb128 (1, NULL);
-	  dw2_asm_output_data (1, DW_LNE_end_sequence, NULL);
-	}
+      FOR_EACH_VEC_ELT (dw_line_info_table_p, separate_line_info, i, table)
+	if (table->in_use)
+	  output_one_line_info_table (table);
     }
 
   /* Output the marker for the end of the line number info.  */
@@ -22113,6 +22004,76 @@ var_location_switch_text_section (void)
   htab_traverse (decl_loc_table, var_location_switch_text_section_1, NULL);
 }
 
+/* Create a new line number table.  */
+
+static dw_line_info_table *
+new_line_info_table (void)
+{
+  dw_line_info_table *table;
+
+  table = ggc_alloc_cleared_dw_line_info_table_struct ();
+  table->file_num = 1;
+  table->line_num = 1;
+  table->is_stmt = DWARF_LINE_DEFAULT_IS_STMT_START;
+
+  return table;
+}
+
+/* Lookup the "current" table into which we emit line info, so
+   that we don't have to do it for every source line.  */
+
+static void
+set_cur_line_info_table (section *sec)
+{
+  dw_line_info_table *table;
+
+  if (sec == text_section)
+    {
+      table = text_section_line_info;
+      if (!table)
+	{
+	  text_section_line_info = table = new_line_info_table ();
+	  table->end_label = text_end_label;
+	}
+    }
+  else if (sec == cold_text_section)
+    {
+      table = cold_text_section_line_info;
+      if (!table)
+	{
+	  cold_text_section_line_info = table = new_line_info_table ();
+	  table->end_label = cold_end_label;
+	}
+    }
+  else
+    {
+      const char *end_label;
+
+      if (flag_reorder_blocks_and_partition)
+	{
+	  if (in_cold_section_p)
+	    end_label = crtl->subsections.cold_section_end_label;
+	  else
+	    end_label = crtl->subsections.hot_section_end_label;
+	}
+      else
+	{
+	  char label[MAX_ARTIFICIAL_LABEL_BYTES];
+	  ASM_GENERATE_INTERNAL_LABEL (label, FUNC_END_LABEL,
+				       current_function_funcdef_no);
+	  end_label = ggc_strdup (label);
+	}
+
+      table = new_line_info_table ();
+      table->end_label = end_label;
+
+      VEC_safe_push (dw_line_info_table_p, gc, separate_line_info, table);
+    }
+
+  cur_line_info_table = table;
+}
+
+
 /* We need to reset the locations at the beginning of each
    function. We can't do this in the end_function hook, because the
    declarations that use the locations won't have been output when
@@ -22121,114 +22082,100 @@ var_location_switch_text_section (void)
 static void
 dwarf2out_begin_function (tree fun)
 {
-  if (function_section (fun) != text_section)
+  section *sec = function_section (fun);
+
+  if (sec != text_section)
     have_multiple_function_sections = true;
+
   if (flag_reorder_blocks_and_partition && !cold_text_section)
     {
       gcc_assert (current_function_decl == fun);
       cold_text_section = unlikely_text_section ();
       switch_to_section (cold_text_section);
       ASM_OUTPUT_LABEL (asm_out_file, cold_text_section_label);
-      switch_to_section (current_function_section ());
+      switch_to_section (sec);
     }
 
   dwarf2out_note_section_used ();
   call_site_count = 0;
   tail_call_site_count = 0;
+
+  set_cur_line_info_table (sec);
+}
+
+/* Add OPCODE+VAL as an entry at the end of the opcode array in TABLE.  */
+
+static void
+push_dw_line_info_entry (dw_line_info_table *table,
+			 enum dw_line_info_opcode opcode, unsigned int val)
+{
+  dw_line_info_entry e;
+  e.opcode = opcode;
+  e.val = val;
+  VEC_safe_push (dw_line_info_entry, gc, table->entries, &e);
 }
 
 /* Output a label to mark the beginning of a source code line entry
    and record information relating to this source line, in
    'line_info_table' for later output of the .debug_line section.  */
+/* ??? The discriminator parameter ought to be unsigned.  */
 
 static void
 dwarf2out_source_line (unsigned int line, const char *filename,
                        int discriminator, bool is_stmt)
 {
-  static bool last_is_stmt = true;
-
-  if (debug_info_level >= DINFO_LEVEL_NORMAL
-      && line != 0)
-    {
-      int file_num = maybe_emit_file (lookup_filename (filename));
+  unsigned int file_num;
+  dw_line_info_table *table;
 
-      switch_to_section (current_function_section ());
+  if (debug_info_level < DINFO_LEVEL_NORMAL || line == 0)
+    return;
 
-      /* If requested, emit something human-readable.  */
-      if (flag_debug_asm)
-	fprintf (asm_out_file, "\t%s %s:%d\n", ASM_COMMENT_START,
-		 filename, line);
+  switch_to_section (current_function_section ());
 
-      if (DWARF2_ASM_LINE_DEBUG_INFO)
-	{
-	  /* Emit the .loc directive understood by GNU as.  */
-	  fprintf (asm_out_file, "\t.loc %d %d 0", file_num, line);
-	  if (is_stmt != last_is_stmt)
-	    {
-	      fprintf (asm_out_file, " is_stmt %d", is_stmt ? 1 : 0);
-	      last_is_stmt = is_stmt;
-	    }
-	  if (SUPPORTS_DISCRIMINATOR && discriminator != 0)
-	    fprintf (asm_out_file, " discriminator %d", discriminator);
-	  fputc ('\n', asm_out_file);
+  /* If requested, emit something human-readable.  */
+  if (flag_debug_asm)
+    fprintf (asm_out_file, "\t%s %s:%d\n", ASM_COMMENT_START, filename, line);
 
-	  /* Indicate that line number info exists.  */
-	  line_info_table_in_use++;
-	}
-      else if (function_section (current_function_decl) != text_section)
-	{
-	  dw_separate_line_info_ref line_info;
-	  targetm.asm_out.internal_label (asm_out_file,
-					  SEPARATE_LINE_CODE_LABEL,
-					  separate_line_info_table_in_use);
-
-	  /* Expand the line info table if necessary.  */
-	  if (separate_line_info_table_in_use
-	      == separate_line_info_table_allocated)
-	    {
-	      separate_line_info_table_allocated += LINE_INFO_TABLE_INCREMENT;
-	      separate_line_info_table
-		= GGC_RESIZEVEC (dw_separate_line_info_entry,
-				 separate_line_info_table,
-				 separate_line_info_table_allocated);
-	      memset (separate_line_info_table
-		       + separate_line_info_table_in_use,
-		      0,
-		      (LINE_INFO_TABLE_INCREMENT
-		       * sizeof (dw_separate_line_info_entry)));
-	    }
+  table = cur_line_info_table;
+  file_num = maybe_emit_file (lookup_filename (filename));
 
-	  /* Add the new entry at the end of the line_info_table.  */
-	  line_info
-	    = &separate_line_info_table[separate_line_info_table_in_use++];
-	  line_info->dw_file_num = file_num;
-	  line_info->dw_line_num = line;
-	  line_info->function = current_function_funcdef_no;
-	}
-      else
-	{
-	  dw_line_info_ref line_info;
+  if (0 && file_num == table->file_num
+      && line == table->line_num
+      && discriminator == table->discrim_num
+      && is_stmt == table->is_stmt)
+    return;
 
-	  targetm.asm_out.internal_label (asm_out_file, LINE_CODE_LABEL,
-				     line_info_table_in_use);
+  if (DWARF2_ASM_LINE_DEBUG_INFO)
+    {
+      /* Emit the .loc directive understood by GNU as.  */
+      fprintf (asm_out_file, "\t.loc %d %d 0", file_num, line);
+      if (is_stmt != table->is_stmt)
+	fprintf (asm_out_file, " is_stmt %d", is_stmt ? 1 : 0);
+      if (SUPPORTS_DISCRIMINATOR && discriminator != 0)
+	fprintf (asm_out_file, " discriminator %d", discriminator);
+      fputc ('\n', asm_out_file);
+    }
+  else
+    {
+      unsigned int label_num = ++line_info_label_num;
 
-	  /* Expand the line info table if necessary.  */
-	  if (line_info_table_in_use == line_info_table_allocated)
-	    {
-	      line_info_table_allocated += LINE_INFO_TABLE_INCREMENT;
-	      line_info_table
-		= GGC_RESIZEVEC (dw_line_info_entry, line_info_table,
-				 line_info_table_allocated);
-	      memset (line_info_table + line_info_table_in_use, 0,
-		      LINE_INFO_TABLE_INCREMENT * sizeof (dw_line_info_entry));
-	    }
+      targetm.asm_out.internal_label (asm_out_file, LINE_CODE_LABEL, label_num);
 
-	  /* Add the new entry at the end of the line_info_table.  */
-	  line_info = &line_info_table[line_info_table_in_use++];
-	  line_info->dw_file_num = file_num;
-	  line_info->dw_line_num = line;
-	}
+      push_dw_line_info_entry (table, LI_set_address, label_num);
+      if (file_num != table->file_num)
+	push_dw_line_info_entry (table, LI_set_file, file_num);
+      if (discriminator != table->discrim_num)
+	push_dw_line_info_entry (table, LI_set_discriminator, discriminator);
+      if (is_stmt != table->is_stmt)
+	push_dw_line_info_entry (table, LI_negate_stmt, 0);
+      push_dw_line_info_entry (table, LI_set_line, line);
     }
+
+  table->file_num = file_num;
+  table->line_num = line;
+  table->discrim_num = discriminator;
+  table->is_stmt = is_stmt;
+  table->in_use = true;
 }
 
 /* Record the beginning of a new source file.  */
@@ -22389,14 +22336,6 @@ dwarf2out_init (const char *filename ATTRIBUTE_UNUSED)
   /* Zero-th entry is allocated, but unused.  */
   abbrev_die_table_in_use = 1;
 
-  /* Allocate the initial hunk of the line_info_table.  */
-  line_info_table = ggc_alloc_cleared_vec_dw_line_info_entry
-    (LINE_INFO_TABLE_INCREMENT);
-  line_info_table_allocated = LINE_INFO_TABLE_INCREMENT;
-
-  /* Zero-th entry is allocated, but unused.  */
-  line_info_table_in_use = 1;
-
   /* Allocate the pubtypes and pubnames vectors.  */
   pubname_table = VEC_alloc (pubname_entry, gc, 32);
   pubtype_table = VEC_alloc (pubname_entry, gc, 32);

^ permalink raw reply	[flat|nested] 6+ messages in thread

end of thread, other threads:[~2011-04-01  2:57 UTC | newest]

Thread overview: 6+ messages (download: mbox.gz / follow: Atom feed)
-- links below jump to the message on this page --
2011-03-30 19:39 [PATCH] PR debug/47471 (set prologue_end in .debug_line) Dodji Seketeli
2011-03-31  6:22 ` Richard Henderson
2011-03-31  9:25   ` Jan Kratochvil
2011-03-31 14:48   ` Dodji Seketeli
2011-03-31 15:42     ` Richard Henderson
2011-04-01  2:57       ` Enhance non-assembler .debug_line output Richard Henderson

This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox;
as well as URLs for read-only IMAP folder(s) and NNTP newsgroup(s).