dwarf2out.c (output_file_names): New function.

* dwarf2out.c (output_file_names): New function.  Compute minimal
        combination of directory and file name table and emit them.
        (output_line_info): Remove code to emit directory and file name
        table and call output_file_names instead.
        (file_info_cmp): Helper function to sort directory names.

From-SVN: r37762
This commit is contained in:
Ulrich Drepper 2000-11-26 19:12:18 +00:00 committed by Ulrich Drepper
parent bdb05a7b49
commit 0b34cf1e97
2 changed files with 331 additions and 54 deletions

View File

@ -1,3 +1,11 @@
2000-11-26 Ulrich Drepper <drepper@redhat.com>
* dwarf2out.c (output_file_names): New function. Compute minimal
combination of directory and file name table and emit them.
(output_line_info): Remove code to emit directory and file name
table and call output_file_names instead.
(file_info_cmp): Helper function to sort directory names.
2000-11-26 Neil Booth <neilb@earthling.net>
* cpplib.h (struct cpp_reader): Remove lang_asm.

View File

@ -529,10 +529,10 @@ static void def_cfa_1 PARAMS ((const char *, dw_cfa_location *));
/* This is similar to the default ASM_OUTPUT_ASCII, except that no trailing
newline is produced. When flag_debug_asm is asserted, we add commentary
at the end of the line, so we must avoid output of a newline here. */
#ifndef ASM_OUTPUT_DWARF_STRING
#define ASM_OUTPUT_DWARF_STRING(FILE,P) \
#ifndef ASM_OUTPUT_DWARF_NSTRING
#define ASM_OUTPUT_DWARF_NSTRING(FILE,P,SLEN) \
do { \
register int slen = strlen(P); \
register int slen = (SLEN); \
register const char *p = (P); \
register int i; \
fprintf (FILE, "\t.ascii \""); \
@ -552,6 +552,8 @@ static void def_cfa_1 PARAMS ((const char *, dw_cfa_location *));
} \
while (0)
#endif
#define ASM_OUTPUT_DWARF_STRING(FILE,P) \
ASM_OUTPUT_DWARF_NSTRING (FILE, P, strlen (P))
/* The DWARF 2 CFA column which tracks the return address. Normally this
is the column for PC, or the first column after all of the hard
@ -1207,7 +1209,7 @@ dwarf2out_stack_adjust (insn)
}
else
return;
if (offset == 0)
return;
@ -3440,6 +3442,7 @@ static void output_pubnames PARAMS ((void));
static void add_arange PARAMS ((tree, dw_die_ref));
static void output_aranges PARAMS ((void));
static void output_line_info PARAMS ((void));
static void output_file_names PARAMS ((void));
static dw_die_ref base_type_die PARAMS ((tree));
static tree root_type PARAMS ((tree));
static int is_base_type PARAMS ((tree));
@ -4645,7 +4648,7 @@ free_AT (a)
case dw_val_class_float:
free (a->dw_attr_val.v.val_float.array);
break;
default:
break;
}
@ -5392,7 +5395,7 @@ break_out_includes (die)
#if 0
/* We can only use this in debugging, since the frontend doesn't check
to make sure that we leave every include file we enter. */
to make sure that we leave every include file we enter. */
if (unit != NULL)
abort ();
#endif
@ -6393,6 +6396,314 @@ output_aranges ()
fputc ('\n', asm_out_file);
}
/* Data structure containing information about input files. */
struct file_info
{
char *path; /* Complete file name. */
char *fname; /* File name part. */
int length; /* Length of entire string. */
int file_idx; /* Index in input file table. */
int dir_idx; /* Index in directory table. */
};
/* Data structure containing information about directories with source
files. */
struct dir_info
{
char *path; /* Path including directory name. */
int length; /* Path length. */
int prefix; /* Index of directory entry which is a prefix. */
int nbytes; /* Total number of bytes in all file names excluding
paths. */
int count; /* Number of files in this directory. */
int dir_idx; /* Index of directory used as base. */
int used; /* Used in the end? */
};
/* Callback function for file_info comparison. We sort by looking at
the directories in the path. */
static int
file_info_cmp (p1, p2)
const void *p1;
const void *p2;
{
const struct file_info *s1 = p1;
const struct file_info *s2 = p2;
unsigned char *cp1;
unsigned char *cp2;
/* Take care of file names without directories. */
if (s1->path == s1->fname)
return -1;
else if (s2->path == s2->fname)
return 1;
cp1 = (unsigned char *) s1->path;
cp2 = (unsigned char *) s2->path;
while (1)
{
++cp1;
++cp2;
/* Reached the end of the first path? */
if (cp1 == (unsigned char *) s1->fname)
/* It doesn't really matter in which order files from the
same directory are sorted in. Therefore don't test for
the second path reaching the end. */
return -1;
else if (cp2 == (unsigned char *) s2->fname)
return 1;
/* Character of current path component the same? */
if (*cp1 != *cp2)
return *cp1 - *cp2;
}
}
/* Output the directory table and the file name table. We try to minimize
the total amount of memory needed. A heuristic is used to avoid large
slowdowns with many input files. */
static void
output_file_names ()
{
struct file_info *files;
struct dir_info *dirs;
int *saved;
int *savehere;
int *backmap;
int ndirs;
int idx_offset;
int i;
int idx;
/* Allocate the various arrays we need. */
files = (struct file_info *) alloca (line_file_table.in_use
* sizeof (struct file_info));
dirs = (struct dir_info *) alloca (line_file_table.in_use
* sizeof (struct dir_info));
/* Sort the file names. */
for (i = 1; i < (int) line_file_table.in_use; ++i)
{
char *f;
/* Skip all leading "./". */
f = line_file_table.table[i];
while (f[0] == '.' && f[1] == '/')
f += 2;
/* Create a new array entry. */
files[i].path = f;
files[i].length = strlen (f);
files[i].file_idx = i;
/* Search for the file name part. */
f = strrchr (f, '/');
files[i].fname = f == NULL ? files[i].path : f + 1;
}
qsort (files + 1, line_file_table.in_use - 1, sizeof (files[0]),
file_info_cmp);
/* Find all the different directories used. */
dirs[0].path = files[1].path;
dirs[0].length = files[1].fname - files[1].path;
dirs[0].prefix = -1;
dirs[0].nbytes = files[1].length - dirs[1].length + 1;
dirs[0].count = 1;
dirs[0].dir_idx = 0;
dirs[0].used = 0;
files[1].dir_idx = 0;
ndirs = 1;
for (i = 2; i < (int) line_file_table.in_use; ++i)
if (files[i].fname - files[i].path == dirs[ndirs - 1].length
&& memcmp (dirs[ndirs - 1].path, files[i].path,
dirs[ndirs - 1].length) == 0)
{
/* Same directory as last entry. */
files[i].dir_idx = ndirs - 1;
dirs[ndirs - 1].nbytes += files[i].length - dirs[ndirs - 1].length + 1;
++dirs[ndirs - 1].count;
}
else
{
int j;
/* This is a new directory. */
dirs[ndirs].path = files[i].path;
dirs[ndirs].length = files[i].fname - files[i].path;
dirs[ndirs].nbytes = files[i].length - dirs[i].length + 1;
dirs[ndirs].count = 1;
dirs[ndirs].dir_idx = ndirs;
dirs[ndirs].used = 0;
files[i].dir_idx = ndirs;
/* Search for a prefix. */
dirs[ndirs].prefix = -1;
for (j = 0; j < ndirs; ++j)
if (dirs[j].length < dirs[ndirs].length
&& dirs[j].length != 0
&& memcmp (dirs[j].path, dirs[ndirs].path, dirs[j].length) == 0)
dirs[ndirs].prefix = j;
++ndirs;
}
/* Now to the actual work. We have to find a subset of the
directories which allow expressing the file name using references
to the directory table with the least amount of characters. We
do not do an exhaustive search where we would have to check out
every combination of every single possible prefix. Instead we
use a heuristic which provides nearly optimal results in most
cases and never is much off. */
saved = (int *) alloca (ndirs * sizeof (int));
savehere = (int *) alloca (ndirs * sizeof (int));
memset (saved, '\0', ndirs * sizeof (saved[0]));
for (i = 0; i < ndirs; ++i)
{
int j;
int total;
/* We can always safe some space for the current directory. But
this does not mean it will be enough to justify adding the
directory. */
savehere[i] = dirs[i].length;
total = (savehere[i] - saved[i]) * dirs[i].count;
for (j = i + 1; j < ndirs; ++j)
{
savehere[j] = 0;
if (saved[j] < dirs[i].length)
{
/* Determine whether the dirs[i] path is a prefix of the
dirs[j] path. */
int k;
k = dirs[j].prefix;
while (k != -1 && k != i)
k = dirs[k].prefix;
if (k == i)
{
/* Yes it is. We can possibly safe some memory but
writing the filenames in dirs[j] relative to
dirs[i]. */
savehere[j] = dirs[i].length;
total += (savehere[j] - saved[j]) * dirs[j].count;
}
}
}
/* Check whether we can safe enough to justify adding the dirs[i]
directory. */
if (total > dirs[i].length + 1)
{
/* It's worthwhile adding. */
for (j = i; j < ndirs; ++j)
if (savehere[j] > 0)
{
/* Remember how much we saved for this directory so far. */
saved[j] = savehere[j];
/* Remember the prefix directory. */
dirs[j].dir_idx = i;
}
}
}
/* We have to emit them in the order they appear in the line_file_table
array since the index is used in the debug info generation. To
do this efficiently we generate a back-mapping of the indices
first. */
backmap = (int *) alloca (line_file_table.in_use * sizeof (int));
for (i = 1; i < (int) line_file_table.in_use; ++i)
{
backmap[files[i].file_idx] = i;
/* Mark this directory as used. */
dirs[dirs[files[i].dir_idx].dir_idx].used = 1;
}
/* That was it. We are ready to emit the information. First the
directory name table. Here we have to make sure that the first
actually emitted directory name has the index one. Zero is
reserved for the current working directory. Make sure we do not
confuse these indices with the one for the constructed table
(even though most of the time they are identical). */
idx = 1;
idx_offset = dirs[0].path[0] == '/' ? 1 : 0;
for (i = 1 - idx_offset; i < ndirs; ++i)
if (dirs[i].used != 0)
{
dirs[i].used = idx++;
if (flag_debug_asm)
{
ASM_OUTPUT_DWARF_NSTRING (asm_out_file,
dirs[i].path, dirs[i].length - 1);
fprintf (asm_out_file, "%s Directory Entry: 0x%x\n",
ASM_COMMENT_START, dirs[i].used);
}
else
{
ASM_OUTPUT_ASCII (asm_out_file, dirs[i].path, dirs[i].length - 1);
ASM_OUTPUT_DWARF_DATA1 (asm_out_file, 0);
fputc ('\n', asm_out_file);
}
}
/* Correct the index for the current working directory entry if it
exists. */
if (idx_offset == 0)
dirs[0].used = 0;
/* Terminate the directory name array. */
ASM_OUTPUT_DWARF_DATA1 (asm_out_file, 0);
if (flag_debug_asm)
fprintf (asm_out_file, "\t%s End directory table", ASM_COMMENT_START);
fputc ('\n', asm_out_file);
/* Now write all the file names. */
for (i = 1; i < (int) line_file_table.in_use; ++i)
{
int file_idx = backmap[i];
int dir_idx = dirs[files[file_idx].dir_idx].dir_idx;
if (flag_debug_asm)
{
ASM_OUTPUT_DWARF_STRING (asm_out_file,
files[file_idx].path
+ dirs[dir_idx].length);
fprintf (asm_out_file, "%s File Entry: 0x%x\n",
ASM_COMMENT_START, i);
}
else
ASM_OUTPUT_ASCII (asm_out_file,
files[file_idx].path + dirs[dir_idx].length,
(files[file_idx].length
- dirs[dir_idx].length) + 1);
/* Include directory index. */
output_uleb128 (dirs[dir_idx].used);
fputc ('\n', asm_out_file);
/* Modification time. */
output_uleb128 (0);
fputc ('\n', asm_out_file);
/* File length in bytes. */
output_uleb128 (0);
fputc ('\n', asm_out_file);
}
/* Terminate the file name table */
ASM_OUTPUT_DWARF_DATA1 (asm_out_file, 0);
if (flag_debug_asm)
fprintf (asm_out_file, "\t%s End file name table", ASM_COMMENT_START);
fputc ('\n', asm_out_file);
}
/* Output the source line number correspondence information. This
information goes into the .debug_line section. */
@ -6403,7 +6714,6 @@ output_line_info ()
char prev_line_label[MAX_ARTIFICIAL_LABEL_BYTES];
register unsigned opc;
register unsigned n_op_args;
register unsigned long ft_index;
register unsigned long lt_index;
register unsigned long current_line;
register long line_offset;
@ -6479,49 +6789,8 @@ output_line_info ()
fputc ('\n', asm_out_file);
}
if (flag_debug_asm)
fprintf (asm_out_file, "%s Include Directory Table\n", ASM_COMMENT_START);
/* Include directory table is empty, at present */
ASM_OUTPUT_DWARF_DATA1 (asm_out_file, 0);
fputc ('\n', asm_out_file);
if (flag_debug_asm)
fprintf (asm_out_file, "%s File Name Table\n", ASM_COMMENT_START);
for (ft_index = 1; ft_index < line_file_table.in_use; ++ft_index)
{
if (flag_debug_asm)
{
ASM_OUTPUT_DWARF_STRING (asm_out_file,
line_file_table.table[ft_index]);
fprintf (asm_out_file, "%s File Entry: 0x%lx",
ASM_COMMENT_START, ft_index);
}
else
{
ASM_OUTPUT_ASCII (asm_out_file,
line_file_table.table[ft_index],
(int) strlen (line_file_table.table[ft_index]) + 1);
}
fputc ('\n', asm_out_file);
/* Include directory index */
output_uleb128 (0);
fputc ('\n', asm_out_file);
/* Modification time */
output_uleb128 (0);
fputc ('\n', asm_out_file);
/* File length in bytes */
output_uleb128 (0);
fputc ('\n', asm_out_file);
}
/* Terminate the file name table */
ASM_OUTPUT_DWARF_DATA1 (asm_out_file, 0);
fputc ('\n', asm_out_file);
/* Write out the information about the files we use. */
output_file_names ();
/* 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
@ -8349,7 +8618,7 @@ tree_add_const_value_attribute (var_die, decl)
default:;
}
}
/* Generate an DW_AT_name attribute given some string value to be included as
the value of the attribute. */
@ -8463,7 +8732,7 @@ add_bound_info (subrange_die, bound_attr, bound)
/* ??? Can this happen, or should the variable have been bound
first? Probably it can, since I imagine that we try to create
the types of parameters in the order in which they exist in
the list, and won't have created a forward reference to a
the list, and won't have created a forward reference to a
later parameter. */
if (decl_die != NULL)
add_AT_die_ref (subrange_die, bound_attr, decl_die);
@ -11053,7 +11322,7 @@ dwarf2out_line (filename, line)
/* Emit the .file and .loc directives understood by GNU as. */
#if 0
/* ??? As of 2000-11-25, gas has a bug in which it doesn't
/* ??? As of 2000-11-25, gas has a bug in which it doesn't
actually use the file number argument. It merely remembers
the last .file directive emitted. */
if (file_num >= old_in_use)
@ -11158,7 +11427,7 @@ dwarf2out_end_source_file ()
{
/* Record the end of the file for break_out_includes. */
new_die (DW_TAG_GNU_EINCL, comp_unit_die);
}
}
}
/* Called from check_newline in c-parse.y. The `buffer' parameter contains