[RFC] More compact (100x) -g3 .debug_gnu_macro (take 5)

Jakub Jelinek jakub@redhat.com
Fri Jul 22 13:49:00 GMT 2011


On Thu, Jul 21, 2011 at 10:10:39AM -0700, Richard Henderson wrote:
> On 07/21/2011 04:22 AM, Jakub Jelinek wrote:
> > Currently, the patch emits 3 byte section headers at the start of
> > the .debug_gnu_macro chunks referenced from .debug_info (through
> > DW_AT_GNU_macros), containing version number (2 byte, 4 ATM) and
> > 1 byte section offset, but the DW_GNU_MACRO_transparent_include
> > referenced sequences don't have it.
> > The .debug_gnu_macro section isn't completely usable without the referencing
> > CUs anyway, so IMHO we could still get away completely without
> > any section header, but if we need it, the question is if
> > the offset size there is useful and if the section header shouldn't
> > go before the transparent_include chains as well (only with that
> > e.g. readelf -wm would be able to dump .debug_gnu_macro without
> > reading .debug_info and tracking offsets to it).
> 
> I've been wondering if the header shouldn't contain the opcode
> definitions, similar to .debug_line, and drop your _define_opcode.
> It does mean that you couldn't re-define opcodes within any one
> sequence, but does that actually seem useful?

Ok, based on further discussions here, on Dwarf-discuss and on IRC
here is a hopefully final version.

Changes since last version:
1) uses .debug_macro section instead of .debug_gnu_macro
2) GNU_MACRO -> MACRO_GNU
3) define_opcode is gone
4) each .debug_macro part has a header, 3+ byte long
   2 byte version (4)
   1 byte flags
	(flag & 1) ? "64-bit DWARF format" : "32-bit DWARF format"
	(flag & 2) ? "lineptr present" : "lineptr missing"
	(flag & 4) ? "defopcode table present" : "defopcode table missing"
  [{4,8} byte lineptr offset (if flag & 2)]
  [1-byte count; count x { 1-byte opcode; uleb128 len; len x { 1-byte DW_FORM_* } } (if flag & 4)]
5) for the defopcode the standard lists DW_FORM_* values that are allowed,
   which rules out e.g. DW_FORM_addr (which would require us to know address size),
   DW_FORM_flag_present (which is meaningless in that case), etc.
Currently GCC emits the base macro sequences with lineptr included, while
the chains referenced from transparent_include with no lineptr and
no DW_MACRO_GNU_*_file in it.  Perhaps we could gain some more savings
by creating a transparent_include chain also from everything after depth > 1
start_file up to (and including) corresponding end_file, if it is at least a
few ops long, probably still by using transparent_includes for the
consecutive define/undef ranges.  The reason for the define/undef only
sequences is now primarily include guards in the headers (different
.debug_line reason is gone with the possibility to put the .debug_line
reference in the header).  By keeping it two level we could have bigger
savings if in several CUs include guards didn't make a difference or the
header inclusion is the same, but still not lose completely if include
guards make a difference.  Anyway, this proposal format allows to add it any
time if it results in significant savings.

DWARF edits:
============================
2.2
Change "Macro information (#define, #undef)" to "Legacy macro information (#define, #undef)".
Add
"DW_AT_macros		Macro information (#define, #undef)"
row to the figure 2.

3.1.1
5. Replace "DW_AT_macro_info" with "DW_AT_macros".  Replace ".debug_macinfo"
with ".debug_macro".  Add at the end of the paragraph
"The DW_AT_macro_info attribute instead might refer to the .debug_macinfo
section as defined in DWARF version 4."

6.3
Replace ".debug_macinfo" with ".debug_macro".
Replace:
"The macro information for each compilation unit is represented as a series
of “macinfo” entries. Each macinfo entry consists of a “type code”
and up to two additional operands."
with:
"The macro information for each compilation unit starts with a section
header followed by a series of “macinfo” entries. Each macinfo entry
consists of a “type code” and zero or more operands."
Add at the end:
"The section header starts with a 2-byte version number, followed by
1-byte flags value.  If the least significant bit (bit 0) in the flags is
cleared, this is 32-bit DWARF format macro section and offsets are 4 byte long,
if it is set, it is 64-bit DWARF format macro section and offsets are 8 byte long.
If the second least significant bit (bit 1) in the flags is set,
the flags byte is followed by an offset in the .debug_line section of the
beginning of the line number information, encoded as 4 byte offset for
32-bit DWARF format macro section and 8 byte offset for 64-bit DWARF format
macro section.  If the third least significant bit (bit 2) in the flags is set,
this is followed by a table describing arguments of the macinfo entry types.
The macinfo entry types defined in this standard may, but might not, be
described in the table, other macinfo entry types used in the section
should be described there.  Vendor extension macinfo entry types should be
allocated in the range from DW_MACRO_lo_user to DW_MACRO_hi_user, other
unassigned codes are reserved for future DWARF standards.
The table starts with a 1-byte count of the defined opcodes, followed by
an entry for each of those opcodes.  Each entry starts with a 1-byte
opcode number, followed by unsigned LEB128 encoded number of arguments
and for each argument there is a single byte describing the form in which
the argument is encoded.  The allowed values are DW_FORM_data1,
DW_FORM_data2, DW_FORM_data4, DW_FORM_data8, DW_FORM_sdata, DW_FORM_udata,
DW_FORM_block, DW_FORM_block1, DW_FORM_block2, DW_FORM_block4, DW_FORM_flag,
DW_FORM_string, DW_FORM_strp and DW_FORM_sec_offset.
This table allows a consumer to skip over unknown macinfo entry types."

6.3.1
Replace:
"DW_MACINFO_define	A macro definition.
DW_MACINFO_undef	A macro undefinition.
DW_MACINFO_start_file	The start of a new source file inclusion.
DW_MACINFO_end_file	The end of the current source file inclusion.
DW_MACINFO_vendor_ext	Vendor specific macro information directives."
with
"DW_MACRO_define		A macro definition.
DW_MACRO_undef			A macro undefinition.
DW_MACRO_start_file		The start of a new source file inclusion.
DW_MACRO_end_file		The end of the current source file inclusion.
DW_MACRO_define_indirect	A macro definition.
DW_MACRO_undef_indirect		A macro undefinition.
DW_MACRO_transparent_include	Include a sequence of entries from given offset."

6.3.1.1
Replace all "DW_MACINFO_define" occurrences with "DW_MACRO_define" and
all "DW_MACINFO_undef" with "DW_MACRO_undef".  Append:
"All DW_MACRO_define_indirect and DW_MACRO_undef_indirect entries have
two operands.  The first operand encodes the line number of the source line
on which the relevant defining or undefining macro directives appeared.
The second operand consists of an offset into a string table contained in
the .debug_str section of the object file.  The size of the operand is
given in the section header offset size.  Apart from the
encoding of the operands these entries are equivalent to DW_MACRO_define
resp. DW_MACRO_undef.

6.3.1.2
Replace all "DW_MACINFO_start_file" occurrences with "DW_MACRO_start_file".

Append: "If any DW_MACINFO_start_file entries are present, the header should
contain a reference to .debug_line section."

6.3.1.3
Replace all "DW_MACINFO_end_file" occurrences with "DW_MACRO_end_file".

6.3.1.4
Replace the whole section with:
"6.3.1.4  Transparent inclusion of a sequence of entries

A DW_MACRO_transparent_include entry has one operand, offset into
another part of the .debug_macro section.  The size of the operand
is given in the section header offset size.  This entry instructs
the consumer to replace this entry with a sequence of macinfo entries found
after the section header at the given .debug_macro offset, up to, but excluding,
the terminating entry with type code 0.  This entry type is aimed at sharing duplicate
sequences of macinfo entries between macinfo from different compilation
units."

6.3.2
Replace "DW_MACINFO_start_file" with "DW_MACRO_start_file" and
"DW_MACINFO_end_file" with "DW_MACRO_end_file".

6.3.3
Replace "DW_MACINFO_define and DW_MACINFO_undef" with
"DW_MACRO_define, DW_MACRO_define_indirect, DW_MACRO_undef and
DW_MACRO_undef_indirect" and replace
"DW_MACINFO_define or DW_MACINFO_undef" with
"DW_MACRO_define, DW_MACRO_define_indirect, DW_MACRO_undef or
DW_MACRO_undef_indirect".
Replace "DW_MACINFO_start_file" with "DW_MACRO_start_file".

6.3.4
Replace ".debug_macinfo" with ".debug_macro".

7.5.4
Replace ".debug_macinfo section to the first byte" with
".debug_macro section to the header".

Add:
"DW_AT_macros	0xXX	macptr"
to figure 20.

7.22
Remove:
"as are the constants in a DW_MACINFO_vendor_ext entry".

Replace figure 39 with:
"Macinfo Type Name		Value
DW_MACRO_define			0x01
DW_MACRO_undef			0x02
DW_MACRO_start_file		0x03
DW_MACRO_end_file		0x04
DW_MACRO_define_indirect	0x05
DW_MACRO_undef_indirect		0x06
DW_MACRO_transparent_include	0x07
DW_MACRO_lo_user		0xe0
DW_MACRO_hi_user		0xff

Figure 39. Macinfo Type Encodings"

Appendix A
Add "DW_AT_macros" to allowable attributes for "DW_TAG_compile_unit"
and "DW_TAG_partial_unit".

Appendix B
Replace "DW_AT_macinfo" with "DW_AT_macros".  Replace
".debug_macinfo" with ".debug_macro".  Add
( .debug_macro ) -> [ DW_MACRO_transparent_include (j) ] -> ( .debug_macro ) and
( .debug_macro ) -> [ DW_MACRO_define_indirect, DW_MACRO_undef_indirect (k) ] -> ( .debug_str )
( .debug_macro ) -> [ DW_MACRO_start_file (l) ] -> ( .debug_line )
to the picture.
In (h) replace ".debug_macinfo" with ".debug_macro".
Add:
(j) .debug_macro A macinfo operand of the form DW_FORM_sec_offset is an
		 offset into another part of the .debug_macro section,
		 to the first macinfo entry in the sequence instead of
		 a section header.
(k) .debug_macro A macinfo operand of the form DW_FORM_strp is an offset
		 into the .debug_str section of the corresponding string.
(l) .debug_macro DW_MACRO_start_file second operand refers to a file entry
		 in the .debug_line section, with the .debug_macro header
		 containing an offset to the start of the referenced
		 .debug_line section."

Appendix F
Change
".debug_macinfo	-	-	-"
to
".debug_macinfo	-	-	-	x"
Add
".debug_macro	x	x	x	5"
row to the table.
============================

Patch has been bootstrapped/regtested on x86_64-linux and i686-linux.
Ok for trunk?

2011-07-22  Jakub Jelinek  <jakub@redhat.com>

	* dwarf2.h (DW_AT_GNU_macros): New.
	(enum dwarf_macro_record_type): New enum.  Add DW_MACRO_GNU_*.

	* dwarf2out.c (struct macinfo_struct): Change code to unsigned char.
	(DEBUG_MACRO_SECTION, DEBUG_MACRO_SECTION_LABEL): Define.
	(dwarf_attr_name): Handle DW_AT_GNU_macros.
	(dwarf2out_define): If the vector is empty and
	lineno is 0, emit a dummy entry first.
	(dwarf2out_undef): Likewise.  Remove redundant semicolon.
	(htab_macinfo_hash, htab_macinfo_eq, output_macinfo_op,
	optimize_macinfo_range): New functions.
	(output_macinfo): Use them.  If !dwarf_strict and .debug_str is
	mergeable, optimize longer strings using
	DW_MACRO_GNU_{define,undef}_indirect and if HAVE_COMDAT_GROUP,
	optimize longer sequences of define/undef ops from headers
	using DW_MACRO_GNU_transparent_include.  For !dwarf_strict
	emit a section headers.
	(dwarf2out_init): For !dwarf_strict set debug_macinfo_section
	and macinfo_section_label to DEBUG_MACRO_SECTION
	resp. DEBUG_MACRO_SECTION_LABEL.
	(dwarf2out_finish): For !dwarf_strict emit DW_AT_GNU_macros
	instead of DW_AT_macro_info.

--- include/dwarf2.h.jj	2011-07-15 20:46:32.000000000 +0200
+++ include/dwarf2.h	2011-07-22 09:06:47.000000000 +0200
@@ -366,6 +366,8 @@ enum dwarf_attribute
     DW_AT_GNU_all_tail_call_sites = 0x2116,
     DW_AT_GNU_all_call_sites = 0x2117,
     DW_AT_GNU_all_source_call_sites = 0x2118,
+    /* Section offset into .debug_macro section.  */
+    DW_AT_GNU_macros = 0x2119,
     /* VMS extensions.  */
     DW_AT_VMS_rtnbeg_pd_address = 0x2201,
     /* GNAT extensions.  */
@@ -879,6 +881,20 @@ enum dwarf_macinfo_record_type
     DW_MACINFO_end_file = 4,
     DW_MACINFO_vendor_ext = 255
   };
+
+/* Names and codes for new style macro information.  */
+enum dwarf_macro_record_type
+  {
+    DW_MACRO_GNU_define = 1,
+    DW_MACRO_GNU_undef = 2,
+    DW_MACRO_GNU_start_file = 3,
+    DW_MACRO_GNU_end_file = 4,
+    DW_MACRO_GNU_define_indirect = 5,
+    DW_MACRO_GNU_undef_indirect = 6,
+    DW_MACRO_GNU_transparent_include = 7,
+    DW_MACRO_GNU_lo_user = 0xe0,
+    DW_MACRO_GNU_hi_user = 0xff
+  };
 

 /* @@@ For use with GNU frame unwind information.  */
 
--- gcc/dwarf2out.c.jj	2011-07-21 09:54:49.000000000 +0200
+++ gcc/dwarf2out.c	2011-07-22 09:18:49.000000000 +0200
@@ -2770,7 +2770,7 @@ struct GTY(()) dw_ranges_struct {
 /* A structure to hold a macinfo entry.  */
 
 typedef struct GTY(()) macinfo_struct {
-  unsigned HOST_WIDE_INT code;
+  unsigned char code;
   unsigned HOST_WIDE_INT lineno;
   const char *info;
 }
@@ -3417,6 +3417,9 @@ static void gen_scheduled_generic_parms_
 #ifndef DEBUG_MACINFO_SECTION
 #define DEBUG_MACINFO_SECTION	".debug_macinfo"
 #endif
+#ifndef DEBUG_MACRO_SECTION
+#define DEBUG_MACRO_SECTION	".debug_macro"
+#endif
 #ifndef DEBUG_LINE_SECTION
 #define DEBUG_LINE_SECTION	".debug_line"
 #endif
@@ -3474,6 +3477,9 @@ static void gen_scheduled_generic_parms_
 #ifndef DEBUG_MACINFO_SECTION_LABEL
 #define DEBUG_MACINFO_SECTION_LABEL     "Ldebug_macinfo"
 #endif
+#ifndef DEBUG_MACRO_SECTION_LABEL
+#define DEBUG_MACRO_SECTION_LABEL	"Ldebug_macro"
+#endif
 
 
 /* Definitions of defaults for formats and names of various special
@@ -4015,6 +4021,8 @@ dwarf_attr_name (unsigned int attr)
       return "DW_AT_GNU_all_call_sites";
     case DW_AT_GNU_all_source_call_sites:
       return "DW_AT_GNU_all_source_call_sites";
+    case DW_AT_GNU_macros:
+      return "DW_AT_GNU_macros";
 
     case DW_AT_GNAT_descriptive_type:
       return "DW_AT_GNAT_descriptive_type";
@@ -20291,6 +20299,15 @@ dwarf2out_define (unsigned int lineno AT
   if (debug_info_level >= DINFO_LEVEL_VERBOSE)
     {
       macinfo_entry e;
+      /* Insert a dummy first entry to be able to optimize the whole
+	 predefined macro block using DW_MACRO_GNU_transparent_include.  */
+      if (VEC_empty (macinfo_entry, macinfo_table) && lineno == 0)
+	{
+	  e.code = 0;
+	  e.lineno = 0;
+	  e.info = NULL;
+	  VEC_safe_push (macinfo_entry, gc, macinfo_table, &e);
+	}
       e.code = DW_MACINFO_define;
       e.lineno = lineno;
       e.info = xstrdup (buffer);;
@@ -20309,58 +20326,386 @@ dwarf2out_undef (unsigned int lineno ATT
   if (debug_info_level >= DINFO_LEVEL_VERBOSE)
     {
       macinfo_entry e;
+      /* Insert a dummy first entry to be able to optimize the whole
+	 predefined macro block using DW_MACRO_GNU_transparent_include.  */
+      if (VEC_empty (macinfo_entry, macinfo_table) && lineno == 0)
+	{
+	  e.code = 0;
+	  e.lineno = 0;
+	  e.info = NULL;
+	  VEC_safe_push (macinfo_entry, gc, macinfo_table, &e);
+	}
       e.code = DW_MACINFO_undef;
       e.lineno = lineno;
-      e.info = xstrdup (buffer);;
+      e.info = xstrdup (buffer);
       VEC_safe_push (macinfo_entry, gc, macinfo_table, &e);
     }
 }
 
+/* Routines to manipulate hash table of CUs.  */
+
+static hashval_t
+htab_macinfo_hash (const void *of)
+{
+  const macinfo_entry *const entry =
+    (const macinfo_entry *) of;
+
+  return htab_hash_string (entry->info);
+}
+
+static int
+htab_macinfo_eq (const void *of1, const void *of2)
+{
+  const macinfo_entry *const entry1 = (const macinfo_entry *) of1;
+  const macinfo_entry *const entry2 = (const macinfo_entry *) of2;
+
+  return !strcmp (entry1->info, entry2->info);
+}
+
+/* Output a single .debug_macinfo entry.  */
+
+static void
+output_macinfo_op (macinfo_entry *ref)
+{
+  int file_num;
+  size_t len;
+  struct indirect_string_node *node;
+  char label[MAX_ARTIFICIAL_LABEL_BYTES];
+
+  switch (ref->code)
+    {
+    case DW_MACINFO_start_file:
+      file_num = maybe_emit_file (lookup_filename (ref->info));
+      dw2_asm_output_data (1, DW_MACINFO_start_file, "Start new file");
+      dw2_asm_output_data_uleb128 (ref->lineno,
+				   "Included from line number %lu", 
+				   (unsigned long) ref->lineno);
+      dw2_asm_output_data_uleb128 (file_num, "file %s", ref->info);
+      break;
+    case DW_MACINFO_end_file:
+      dw2_asm_output_data (1, DW_MACINFO_end_file, "End file");
+      break;
+    case DW_MACINFO_define:
+    case DW_MACINFO_undef:
+      len = strlen (ref->info) + 1;
+      if (!dwarf_strict
+	  && len > DWARF_OFFSET_SIZE
+	  && !DWARF2_INDIRECT_STRING_SUPPORT_MISSING_ON_TARGET
+	  && (debug_str_section->common.flags & SECTION_MERGE) != 0)
+	{
+	  ref->code = ref->code == DW_MACINFO_define
+		      ? DW_MACRO_GNU_define_indirect
+		      : DW_MACRO_GNU_undef_indirect;
+	  output_macinfo_op (ref);
+	  return;
+	}
+      dw2_asm_output_data (1, ref->code,
+			   ref->code == DW_MACINFO_define
+			   ? "Define macro" : "Undefine macro");
+      dw2_asm_output_data_uleb128 (ref->lineno, "At line number %lu", 
+				   (unsigned long) ref->lineno);
+      dw2_asm_output_nstring (ref->info, -1, "The macro");
+      break;
+    case DW_MACRO_GNU_define_indirect:
+    case DW_MACRO_GNU_undef_indirect:
+      node = find_AT_string (ref->info);
+      if (node->form != DW_FORM_strp)
+	{
+	  char label[32];
+	  ASM_GENERATE_INTERNAL_LABEL (label, "LASF", dw2_string_counter);
+	  ++dw2_string_counter;
+	  node->label = xstrdup (label);
+	  node->form = DW_FORM_strp;
+	}
+      dw2_asm_output_data (1, ref->code,
+			   ref->code == DW_MACRO_GNU_define_indirect
+			   ? "Define macro indirect"
+			   : "Undefine macro indirect");
+      dw2_asm_output_data_uleb128 (ref->lineno, "At line number %lu",
+				   (unsigned long) ref->lineno);
+      dw2_asm_output_offset (DWARF_OFFSET_SIZE, node->label,
+			     debug_str_section, "The macro: \"%s\"",
+			     ref->info);
+      break;
+    case DW_MACRO_GNU_transparent_include:
+      dw2_asm_output_data (1, ref->code, "Transparent include");
+      ASM_GENERATE_INTERNAL_LABEL (label,
+				   DEBUG_MACRO_SECTION_LABEL, ref->lineno);
+      dw2_asm_output_offset (DWARF_OFFSET_SIZE, label, NULL, NULL);
+      break;
+    default:
+      fprintf (asm_out_file, "%s unrecognized macinfo code %lu\n",
+	       ASM_COMMENT_START, (unsigned long) ref->code);
+      break;
+    }
+}
+
+/* Attempt to make a sequence of define/undef macinfo ops shareable with
+   other compilation unit .debug_macinfo sections.  IDX is the first
+   index of a define/undef, return the number of ops that should be
+   emitted in a comdat .debug_macinfo section and emit
+   a DW_MACRO_GNU_transparent_include entry referencing it.
+   If the define/undef entry should be emitted normally, return 0.  */
+
+static unsigned
+optimize_macinfo_range (unsigned int idx, VEC (macinfo_entry, gc) *files,
+			htab_t *macinfo_htab)
+{
+  macinfo_entry *first, *second, *cur, *inc;
+  char linebuf[sizeof (HOST_WIDE_INT) * 3 + 1];
+  unsigned char checksum[16];
+  struct md5_ctx ctx;
+  char *grp_name, *tail;
+  const char *base;
+  unsigned int i, count, encoded_filename_len, linebuf_len;
+  void **slot;
+
+  first = VEC_index (macinfo_entry, macinfo_table, idx);
+  second = VEC_index (macinfo_entry, macinfo_table, idx + 1);
+
+  /* Optimize only if there are at least two consecutive define/undef ops,
+     and either all of them are before first DW_MACINFO_start_file
+     with lineno 0 (i.e. predefined macro block), or all of them are
+     in some included header file.  */
+  if (second->code != DW_MACINFO_define && second->code != DW_MACINFO_undef)
+    return 0;
+  if (VEC_empty (macinfo_entry, files))
+    {
+      if (first->lineno != 0 || second->lineno != 0)
+	return 0;
+    }
+  else if (first->lineno == 0)
+    return 0;
+
+  /* Find the last define/undef entry that can be grouped together
+     with first and at the same time compute md5 checksum of their
+     codes, linenumbers and strings.  */
+  md5_init_ctx (&ctx);
+  for (i = idx; VEC_iterate (macinfo_entry, macinfo_table, i, cur); i++)
+    if (cur->code != DW_MACINFO_define && cur->code != DW_MACINFO_undef)
+      break;
+    else if (first->lineno == 0 && cur->lineno != 0)
+      break;
+    else
+      {
+	unsigned char code = cur->code;
+	md5_process_bytes (&code, 1, &ctx);
+	checksum_uleb128 (cur->lineno, &ctx);
+	md5_process_bytes (cur->info, strlen (cur->info) + 1, &ctx);
+      }
+  md5_finish_ctx (&ctx, checksum);
+  count = i - idx;
+
+  /* From the containing include filename (if any) pick up just
+     usable characters from its basename.  */
+  if (first->lineno == 0)
+    base = "";
+  else
+    base = lbasename (VEC_last (macinfo_entry, files)->info);
+  for (encoded_filename_len = 0, i = 0; base[i]; i++)
+    if (ISIDNUM (base[i]) || base[i] == '.')
+      encoded_filename_len++;
+  /* Count . at the end.  */
+  if (encoded_filename_len)
+    encoded_filename_len++;
+
+  sprintf (linebuf, HOST_WIDE_INT_PRINT_UNSIGNED, first->lineno);
+  linebuf_len = strlen (linebuf);
+
+  /* The group name format is: wmN.[<encoded filename>.]<lineno>.<md5sum>  */
+  grp_name = XNEWVEC (char, 4 + encoded_filename_len + linebuf_len + 1
+		      + 16 * 2 + 1);
+  memcpy (grp_name, DWARF_OFFSET_SIZE == 4 ? "wm4." : "wm8.", 4);
+  tail = grp_name + 4;
+  if (encoded_filename_len)
+    {
+      for (i = 0; base[i]; i++)
+	if (ISIDNUM (base[i]) || base[i] == '.')
+	  *tail++ = base[i];
+      *tail++ = '.';
+    }
+  memcpy (tail, linebuf, linebuf_len);
+  tail += linebuf_len;
+  *tail++ = '.';
+  for (i = 0; i < 16; i++)
+    sprintf (tail + i * 2, "%02x", checksum[i] & 0xff);
+
+  /* Construct a macinfo_entry for DW_MACRO_GNU_transparent_include
+     in the empty vector entry before the first define/undef.  */
+  inc = VEC_index (macinfo_entry, macinfo_table, idx - 1);
+  inc->code = DW_MACRO_GNU_transparent_include;
+  inc->lineno = 0;
+  inc->info = grp_name;
+  if (*macinfo_htab == NULL)
+    *macinfo_htab = htab_create (10, htab_macinfo_hash, htab_macinfo_eq, NULL);
+  /* Avoid emitting duplicates.  */
+  slot = htab_find_slot (*macinfo_htab, inc, INSERT);
+  if (*slot != NULL)
+    {
+      free (CONST_CAST (char *, inc->info));
+      inc->code = 0;
+      inc->info = NULL;
+      /* If such an entry has been used before, just emit
+	 a DW_MACRO_GNU_transparent_include op.  */
+      inc = (macinfo_entry *) *slot;
+      output_macinfo_op (inc);
+      /* And clear all macinfo_entry in the range to avoid emitting them
+	 in the second pass.  */
+      for (i = idx;
+	   VEC_iterate (macinfo_entry, macinfo_table, i, cur)
+	   && i < idx + count;
+	   i++)
+	{
+	  cur->code = 0;
+	  free (CONST_CAST (char *, cur->info));
+	  cur->info = NULL;
+	}
+    }
+  else
+    {
+      *slot = inc;
+      inc->lineno = htab_elements (*macinfo_htab);
+      output_macinfo_op (inc);
+    }
+  return count;
+}
+
+/* Output macinfo section(s).  */
+
 static void
 output_macinfo (void)
 {
   unsigned i;
   unsigned long length = VEC_length (macinfo_entry, macinfo_table);
   macinfo_entry *ref;
+  VEC (macinfo_entry, gc) *files = NULL;
+  htab_t macinfo_htab = NULL;
 
   if (! length)
     return;
 
+  /* output_macinfo* uses these interchangeably.  */
+  gcc_assert ((int) DW_MACINFO_define == (int) DW_MACRO_GNU_define
+	      && (int) DW_MACINFO_undef == (int) DW_MACRO_GNU_undef
+	      && (int) DW_MACINFO_start_file == (int) DW_MACRO_GNU_start_file
+	      && (int) DW_MACINFO_end_file == (int) DW_MACRO_GNU_end_file);
+
+  /* For .debug_macro emit the section header.  */
+  if (!dwarf_strict)
+    {
+      dw2_asm_output_data (2, 4, "DWARF macro version number");
+      if (DWARF_OFFSET_SIZE == 8)
+	dw2_asm_output_data (1, 3, "Flags: 64-bit, lineptr present");
+      else
+	dw2_asm_output_data (1, 2, "Flags: 32-bit, lineptr present");
+      dw2_asm_output_offset (DWARF_OFFSET_SIZE, debug_line_section_label,
+			     debug_line_section, NULL);
+    }
+
+  /* In the first loop, it emits the primary .debug_macinfo section
+     and after each emitted op the macinfo_entry is cleared.
+     If a longer range of define/undef ops can be optimized using
+     DW_MACRO_GNU_transparent_include, the
+     DW_MACRO_GNU_transparent_include op is emitted and kept in
+     the vector before the first define/undef in the range and the
+     whole range of define/undef ops is not emitted and kept.  */
   for (i = 0; VEC_iterate (macinfo_entry, macinfo_table, i, ref); i++)
     {
       switch (ref->code)
 	{
-	  case DW_MACINFO_start_file:
+	case DW_MACINFO_start_file:
+	  VEC_safe_push (macinfo_entry, gc, files, ref);
+	  break;
+	case DW_MACINFO_end_file:
+	  if (!VEC_empty (macinfo_entry, files))
 	    {
-	      int file_num = maybe_emit_file (lookup_filename (ref->info));
-	      dw2_asm_output_data (1, DW_MACINFO_start_file, "Start new file");
-	      dw2_asm_output_data_uleb128 
-			(ref->lineno, "Included from line number %lu", 
-			 			(unsigned long)ref->lineno);
-	      dw2_asm_output_data_uleb128 (file_num, "file %s", ref->info);
+	      macinfo_entry *file = VEC_last (macinfo_entry, files);
+	      free (CONST_CAST (char *, file->info));
+	      VEC_pop (macinfo_entry, files);
 	    }
-	    break;
-	  case DW_MACINFO_end_file:
-	    dw2_asm_output_data (1, DW_MACINFO_end_file, "End file");
-	    break;
-	  case DW_MACINFO_define:
-	    dw2_asm_output_data (1, DW_MACINFO_define, "Define macro");
-	    dw2_asm_output_data_uleb128 (ref->lineno, "At line number %lu", 
-			 			(unsigned long)ref->lineno);
-	    dw2_asm_output_nstring (ref->info, -1, "The macro");
-	    break;
-	  case DW_MACINFO_undef:
-	    dw2_asm_output_data (1, DW_MACINFO_undef, "Undefine macro");
-	    dw2_asm_output_data_uleb128 (ref->lineno, "At line number %lu",
-			 			(unsigned long)ref->lineno);
-	    dw2_asm_output_nstring (ref->info, -1, "The macro");
-	    break;
-	  default:
-	   fprintf (asm_out_file, "%s unrecognized macinfo code %lu\n",
-	     ASM_COMMENT_START, (unsigned long)ref->code);
+	  break;
+	case DW_MACINFO_define:
+	case DW_MACINFO_undef:
+	  if (!dwarf_strict
+	      && HAVE_COMDAT_GROUP
+	      && VEC_length (macinfo_entry, files) != 1
+	      && i > 0
+	      && i + 1 < length
+	      && VEC_index (macinfo_entry, macinfo_table, i - 1)->code == 0)
+	    {
+	      unsigned count = optimize_macinfo_range (i, files, &macinfo_htab);
+	      if (count)
+		{
+		  i += count - 1;
+		  continue;
+		}
+	    }
+	  break;
+	case 0:
+	  /* A dummy entry may be inserted at the beginning to be able
+	     to optimize the whole block of predefined macros.  */
+	  if (i == 0)
+	    continue;
+	default:
 	  break;
 	}
+      output_macinfo_op (ref);
+      /* For DW_MACINFO_start_file ref->info has been copied into files
+	 vector.  */
+      if (ref->code != DW_MACINFO_start_file)
+	free (CONST_CAST (char *, ref->info));
+      ref->info = NULL;
+      ref->code = 0;
     }
+
+  if (macinfo_htab == NULL)
+    return;
+
+  htab_delete (macinfo_htab);
+
+  /* If any DW_MACRO_GNU_transparent_include were used, on those
+     DW_MACRO_GNU_transparent_include entries terminate the
+     current chain and switch to a new comdat .debug_macinfo
+     section and emit the define/undef entries within it.  */
+  for (i = 0; VEC_iterate (macinfo_entry, macinfo_table, i, ref); i++)
+    switch (ref->code)
+      {
+      case 0:
+	continue;
+      case DW_MACRO_GNU_transparent_include:
+	{
+	  char label[MAX_ARTIFICIAL_LABEL_BYTES];
+	  tree comdat_key = get_identifier (ref->info);
+	  /* Terminate the previous .debug_macinfo section.  */
+	  dw2_asm_output_data (1, 0, "End compilation unit");
+	  targetm.asm_out.named_section (DEBUG_MACRO_SECTION,
+					 SECTION_DEBUG
+					 | SECTION_LINKONCE,
+					 comdat_key);
+	  ASM_GENERATE_INTERNAL_LABEL (label,
+				       DEBUG_MACRO_SECTION_LABEL,
+				       ref->lineno);
+	  ASM_OUTPUT_LABEL (asm_out_file, label);
+	  ref->code = 0;
+	  free (CONST_CAST (char *, ref->info));
+	  ref->info = NULL;
+	  dw2_asm_output_data (2, 4, "DWARF macro version number");
+	  if (DWARF_OFFSET_SIZE == 8)
+	    dw2_asm_output_data (1, 1, "Flags: 64-bit");
+	  else
+	    dw2_asm_output_data (1, 0, "Flags: 32-bit");
+	}
+	break;
+      case DW_MACINFO_define:
+      case DW_MACINFO_undef:
+	output_macinfo_op (ref);
+	ref->code = 0;
+	free (CONST_CAST (char *, ref->info));
+	ref->info = NULL;
+	break;
+      default:
+	gcc_unreachable ();
+      }
 }
 
 /* Set up for Dwarf output at the start of compilation.  */
@@ -20409,7 +20754,9 @@ dwarf2out_init (const char *filename ATT
 				      SECTION_DEBUG, NULL);
   debug_aranges_section = get_section (DEBUG_ARANGES_SECTION,
 				       SECTION_DEBUG, NULL);
-  debug_macinfo_section = get_section (DEBUG_MACINFO_SECTION,
+  debug_macinfo_section = get_section (dwarf_strict
+				       ? DEBUG_MACINFO_SECTION
+				       : DEBUG_MACRO_SECTION,
 				       SECTION_DEBUG, NULL);
   debug_line_section = get_section (DEBUG_LINE_SECTION,
 				    SECTION_DEBUG, NULL);
@@ -20441,7 +20788,9 @@ dwarf2out_init (const char *filename ATT
   ASM_GENERATE_INTERNAL_LABEL (ranges_section_label,
 			       DEBUG_RANGES_SECTION_LABEL, 0);
   ASM_GENERATE_INTERNAL_LABEL (macinfo_section_label,
-			       DEBUG_MACINFO_SECTION_LABEL, 0);
+			       dwarf_strict
+			       ? DEBUG_MACINFO_SECTION_LABEL
+			       : DEBUG_MACRO_SECTION_LABEL, 0);
 
   if (debug_info_level >= DINFO_LEVEL_VERBOSE)
     macinfo_table = VEC_alloc (macinfo_entry, gc, 64);
@@ -21984,7 +22333,9 @@ dwarf2out_finish (const char *filename)
 		    debug_line_section_label);
 
   if (debug_info_level >= DINFO_LEVEL_VERBOSE)
-    add_AT_macptr (comp_unit_die (), DW_AT_macro_info, macinfo_section_label);
+    add_AT_macptr (comp_unit_die (),
+		   dwarf_strict ? DW_AT_macro_info : DW_AT_GNU_macros,
+		   macinfo_section_label);
 
   if (have_location_lists)
     optimize_location_lists (comp_unit_die ());


	Jakub



More information about the Gcc-patches mailing list