Commit cb9e4555 by Zdenek Dvorak Committed by Zdenek Dvorak

gcov-dump.c (print_prefix): Fix signedness warning.

	* gcov-dump.c (print_prefix): Fix signedness warning.
	* gcov-io.h (struct counter_section, struct counter_section_data): New.
	(struct function_info): n_arc_counts field removed, n_counter_sections,
	counter_sections fields added.
	(struct gcov_info): arc_counts, n_arc_counts fields removed,
	n_counter_sections, counter_sections fields added.
	* libgcov.c (gcov_exit, __gcov_flush): Add support for multiple
	profile sections.
	* profile.h (MAX_COUNTER_SECTIONS): New.
	(struct section_info): New.
	(struct profile_info): count_instrumented_edges,
	count_edges_instrumented_now fields removed, n_sections, section_info
	fields added.
	(find_counters_section): Declare.
	* profile.c (struct function_list): count_edges field removed,
	n_counter_sections, counter_sections fields added.
	(set_purpose, label_for_tag, build_counter_section_fields,
	build_counter_section_value, build_counter_section_data_fields,
	build_counter_section_data_value, build_function_info_fields,
	build_function_info_value, build_gcov_info_fields,
	build_gcov_info_value): New static functions.
	(find_counters_section): New function.
	(instrument_edges, get_exec_counts, compute_branch_probabilities,
	branch_prob, create_profiler): Modified to support multiple profile
	sections.

From-SVN: r63474
parent b0d7ef9a
2003-02-26 Zdenek Dvorak <rakdver@atrey.karlin.mff.cuni.cz>
* gcov-dump.c (print_prefix): Fix signedness warning.
* gcov-io.h (struct counter_section, struct counter_section_data): New.
(struct function_info): n_arc_counts field removed, n_counter_sections,
counter_sections fields added.
(struct gcov_info): arc_counts, n_arc_counts fields removed,
n_counter_sections, counter_sections fields added.
* libgcov.c (gcov_exit, __gcov_flush): Add support for multiple
profile sections.
* profile.h (MAX_COUNTER_SECTIONS): New.
(struct section_info): New.
(struct profile_info): count_instrumented_edges,
count_edges_instrumented_now fields removed, n_sections, section_info
fields added.
(find_counters_section): Declare.
* profile.c (struct function_list): count_edges field removed,
n_counter_sections, counter_sections fields added.
(set_purpose, label_for_tag, build_counter_section_fields,
build_counter_section_value, build_counter_section_data_fields,
build_counter_section_data_value, build_function_info_fields,
build_function_info_value, build_gcov_info_fields,
build_gcov_info_value): New static functions.
(find_counters_section): New function.
(instrument_edges, get_exec_counts, compute_branch_probabilities,
branch_prob, create_profiler): Modified to support multiple profile
sections.
2003-02-26 John David Anglin <dave.anglin@nrc-cnrc.gc.ca> 2003-02-26 John David Anglin <dave.anglin@nrc-cnrc.gc.ca>
* pa.c (compute_frame_size): Don't assume PREFERRED_STACK_BOUNDARY * pa.c (compute_frame_size): Don't assume PREFERRED_STACK_BOUNDARY
......
...@@ -131,7 +131,7 @@ print_prefix (filename, depth) ...@@ -131,7 +131,7 @@ print_prefix (filename, depth)
{ {
static const char prefix[] = " "; static const char prefix[] = " ";
printf ("%s:%.*s", filename, depth, prefix); printf ("%s:%.*s", filename, (int) depth, prefix);
} }
static void static void
......
...@@ -216,16 +216,33 @@ struct gcov_summary ...@@ -216,16 +216,33 @@ struct gcov_summary
gcov_type arc_sum_max; /* sum of max_one */ gcov_type arc_sum_max; /* sum of max_one */
}; };
#if IN_LIBGCC2
/* Structures embedded in coveraged program. The structures generated /* Structures embedded in coveraged program. The structures generated
by write_profile must match these. */ by write_profile must match these. */
/* Information about section of counters for a function. */
struct counter_section
{
unsigned tag; /* Tag of the section. */
unsigned n_counters; /* Number of counters in the section. */
};
#if IN_LIBGCC2
/* Information about section of counters for an object file. */
struct counter_section_data
{
unsigned tag; /* Tag of the section. */
unsigned n_counters; /* Number of counters in the section. */
gcov_type *counters; /* The data. */
};
/* Information about a single function. */ /* Information about a single function. */
struct function_info struct function_info
{ {
const char *name; /* (mangled) name of function */ const char *name; /* (mangled) name of function */
unsigned checksum; /* function checksum */ unsigned checksum; /* function checksum */
unsigned n_arc_counts; /* number of instrumented arcs */ unsigned n_counter_sections; /* Number of types of counters */
const struct counter_section *counter_sections;
/* The section descriptions */
}; };
/* Information about a single object file. */ /* Information about a single object file. */
...@@ -237,11 +254,12 @@ struct gcov_info ...@@ -237,11 +254,12 @@ struct gcov_info
const char *filename; /* output file name */ const char *filename; /* output file name */
long wkspc; /* libgcc workspace */ long wkspc; /* libgcc workspace */
const struct function_info *functions; /* table of functions */
unsigned n_functions; /* number of functions */ unsigned n_functions; /* number of functions */
const struct function_info *functions; /* table of functions */
gcov_type *arc_counts; /* table of arc counts */ unsigned n_counter_sections; /* Number of types of counters */
unsigned n_arc_counts; /* number of arc counts */ const struct counter_section_data *counter_sections;
/* The data to be put into the sections. */
}; };
/* Register a new object file module. */ /* Register a new object file module. */
......
...@@ -112,14 +112,35 @@ gcov_exit (void) ...@@ -112,14 +112,35 @@ gcov_exit (void)
int merging = 0; int merging = 0;
long base; long base;
const struct function_info *fn_info; const struct function_info *fn_info;
gcov_type **counters;
gcov_type *count_ptr; gcov_type *count_ptr;
gcov_type object_max_one = 0; gcov_type object_max_one = 0;
gcov_type count;
unsigned tag, length, flength, checksum;
unsigned arc_data_index, f_sect_index, sect_index;
ptr->wkspc = 0; ptr->wkspc = 0;
if (!ptr->filename) if (!ptr->filename)
continue; continue;
for (ix = ptr->n_arc_counts, count_ptr = ptr->arc_counts; ix--;) counters = malloc (sizeof (gcov_type *) * ptr->n_counter_sections);
for (ix = 0; ix < ptr->n_counter_sections; ix++)
counters[ix] = ptr->counter_sections[ix].counters;
for (arc_data_index = 0;
arc_data_index < ptr->n_counter_sections
&& ptr->counter_sections[arc_data_index].tag != GCOV_TAG_ARC_COUNTS;
arc_data_index++)
continue;
if (arc_data_index == ptr->n_counter_sections)
{
/* For now; later we may want to just measure other profiles,
but now I am lazy to check for all consequences. */
abort ();
}
for (ix = ptr->counter_sections[arc_data_index].n_counters,
count_ptr = ptr->counter_sections[arc_data_index].counters; ix--;)
{ {
gcov_type count = *count_ptr++; gcov_type count = *count_ptr++;
...@@ -155,7 +176,6 @@ gcov_exit (void) ...@@ -155,7 +176,6 @@ gcov_exit (void)
if (merging) if (merging)
{ {
/* Merge data from file. */ /* Merge data from file. */
unsigned tag, length;
if (gcov_read_unsigned (da_file, &tag) || tag != GCOV_DATA_MAGIC) if (gcov_read_unsigned (da_file, &tag) || tag != GCOV_DATA_MAGIC)
{ {
...@@ -173,7 +193,6 @@ gcov_exit (void) ...@@ -173,7 +193,6 @@ gcov_exit (void)
} }
/* Merge execution counts for each function. */ /* Merge execution counts for each function. */
count_ptr = ptr->arc_counts;
for (ix = ptr->n_functions, fn_info = ptr->functions; for (ix = ptr->n_functions, fn_info = ptr->functions;
ix--; fn_info++) ix--; fn_info++)
{ {
...@@ -194,33 +213,40 @@ gcov_exit (void) ...@@ -194,33 +213,40 @@ gcov_exit (void)
ptr->filename, fn_info->name); ptr->filename, fn_info->name);
goto read_fatal; goto read_fatal;
} }
{
unsigned flength, checksum; if (gcov_read_unsigned (da_file, &flength)
|| gcov_skip_string (da_file, flength)
if (gcov_read_unsigned (da_file, &flength) || gcov_read_unsigned (da_file, &checksum))
|| gcov_skip_string (da_file, flength)
|| gcov_read_unsigned (da_file, &checksum))
goto read_error;
if (flength != strlen (fn_info->name)
|| checksum != fn_info->checksum)
goto read_mismatch;
}
/* Check arc counts */
if (gcov_read_unsigned (da_file, &tag)
|| gcov_read_unsigned (da_file, &length))
goto read_error; goto read_error;
if (tag != GCOV_TAG_ARC_COUNTS if (flength != strlen (fn_info->name)
|| length / 8 != fn_info->n_arc_counts) || checksum != fn_info->checksum)
goto read_mismatch; goto read_mismatch;
{
gcov_type count; /* Counters. */
for (f_sect_index = 0;
for (jx = fn_info->n_arc_counts; jx--; count_ptr++) f_sect_index < fn_info->n_counter_sections;
if (gcov_read_counter (da_file, &count)) f_sect_index++)
{
if (gcov_read_unsigned (da_file, &tag)
|| gcov_read_unsigned (da_file, &length))
goto read_error; goto read_error;
else for (sect_index = 0;
*count_ptr += count; sect_index < ptr->n_counter_sections;
} sect_index++)
if (ptr->counter_sections[sect_index].tag == tag)
break;
if (fn_info->counter_sections[f_sect_index].tag != tag
|| sect_index == ptr->n_counter_sections
|| length / 8 != fn_info->counter_sections[f_sect_index].n_counters)
goto read_mismatch;
for (jx = fn_info->counter_sections[f_sect_index].n_counters;
jx--; counters[sect_index]++)
if (gcov_read_counter (da_file, &count))
goto read_error;
else
*counters[sect_index] += count;
}
} }
/* Check object summary */ /* Check object summary */
...@@ -279,7 +305,7 @@ gcov_exit (void) ...@@ -279,7 +305,7 @@ gcov_exit (void)
} }
object.runs++; object.runs++;
object.arcs = ptr->n_arc_counts; object.arcs = ptr->counter_sections[arc_data_index].n_counters;
object.arc_sum = 0; object.arc_sum = 0;
if (object.arc_max_one < object_max_one) if (object.arc_max_one < object_max_one)
object.arc_max_one = object_max_one; object.arc_max_one = object_max_one;
...@@ -299,7 +325,8 @@ gcov_exit (void) ...@@ -299,7 +325,8 @@ gcov_exit (void)
} }
/* Write execution counts for each function. */ /* Write execution counts for each function. */
count_ptr = ptr->arc_counts; for (ix = 0; ix < ptr->n_counter_sections; ix++)
counters[ix] = ptr->counter_sections[ix].counters;
for (ix = ptr->n_functions, fn_info = ptr->functions; ix--; fn_info++) for (ix = ptr->n_functions, fn_info = ptr->functions; ix--; fn_info++)
{ {
/* Announce function. */ /* Announce function. */
...@@ -312,24 +339,41 @@ gcov_exit (void) ...@@ -312,24 +339,41 @@ gcov_exit (void)
|| gcov_write_unsigned (da_file, fn_info->checksum) || gcov_write_unsigned (da_file, fn_info->checksum)
|| gcov_write_length (da_file, base)) || gcov_write_length (da_file, base))
goto write_error; goto write_error;
/* arc counts. */ /* counters. */
if (gcov_write_unsigned (da_file, GCOV_TAG_ARC_COUNTS) for (f_sect_index = 0;
|| !(base = gcov_reserve_length (da_file))) f_sect_index < fn_info->n_counter_sections;
goto write_error; f_sect_index++)
for (jx = fn_info->n_arc_counts; jx--;)
{ {
gcov_type count = *count_ptr++; tag = fn_info->counter_sections[f_sect_index].tag;
for (sect_index = 0;
sect_index < ptr->n_counter_sections;
sect_index++)
if (ptr->counter_sections[sect_index].tag == tag)
break;
if (sect_index == ptr->n_counter_sections)
abort ();
if (gcov_write_unsigned (da_file, tag)
|| !(base = gcov_reserve_length (da_file)))
goto write_error;
for (jx = fn_info->counter_sections[f_sect_index].n_counters; jx--;)
{
gcov_type count = *counters[sect_index]++;
object.arc_sum += count; if (tag == GCOV_TAG_ARC_COUNTS)
if (object.arc_max_sum < count) {
object.arc_max_sum = count; object.arc_sum += count;
if (gcov_write_counter (da_file, count)) if (object.arc_max_sum < count)
goto write_error; /* RIP Edsger Dijkstra */ object.arc_max_sum = count;
}
if (gcov_write_counter (da_file, count))
goto write_error; /* RIP Edsger Dijkstra */
}
if (gcov_write_length (da_file, base))
goto write_error;
} }
if (gcov_write_length (da_file, base))
goto write_error;
} }
/* Object file summary. */ /* Object file summary. */
...@@ -367,11 +411,12 @@ gcov_exit (void) ...@@ -367,11 +411,12 @@ gcov_exit (void)
} }
else else
{ {
program_arcs += ptr->n_arc_counts; program_arcs += ptr->counter_sections[arc_data_index].n_counters;
program_sum += object.arc_sum; program_sum += object.arc_sum;
if (program_max_sum < object.arc_max_sum) if (program_max_sum < object.arc_max_sum)
program_max_sum = object.arc_max_sum; program_max_sum = object.arc_max_sum;
} }
free(counters);
} }
/* Generate whole program statistics. */ /* Generate whole program statistics. */
...@@ -465,9 +510,10 @@ __gcov_flush (void) ...@@ -465,9 +510,10 @@ __gcov_flush (void)
gcov_exit (); gcov_exit ();
for (ptr = gcov_list; ptr; ptr = ptr->next) for (ptr = gcov_list; ptr; ptr = ptr->next)
{ {
unsigned i; unsigned i, j;
for (i = ptr->n_arc_counts; i--;) for (j = 0; j < ptr->n_counter_sections; j++)
ptr->arc_counts[i] = 0; for (i = ptr->counter_sections[j].n_counters; i--;)
ptr->counter_sections[j].counters[i] = 0;
} }
} }
...@@ -96,7 +96,9 @@ struct function_list ...@@ -96,7 +96,9 @@ struct function_list
struct function_list *next; /* next function */ struct function_list *next; /* next function */
const char *name; /* function name */ const char *name; /* function name */
unsigned cfg_checksum; /* function checksum */ unsigned cfg_checksum; /* function checksum */
unsigned count_edges; /* number of intrumented edges */ unsigned n_counter_sections; /* number of counter sections */
struct counter_section counter_sections[MAX_COUNTER_SECTIONS];
/* the sections */
}; };
static struct function_list *functions_head = 0; static struct function_list *functions_head = 0;
...@@ -156,6 +158,16 @@ static gcov_type * get_exec_counts PARAMS ((void)); ...@@ -156,6 +158,16 @@ static gcov_type * get_exec_counts PARAMS ((void));
static unsigned compute_checksum PARAMS ((void)); static unsigned compute_checksum PARAMS ((void));
static basic_block find_group PARAMS ((basic_block)); static basic_block find_group PARAMS ((basic_block));
static void union_groups PARAMS ((basic_block, basic_block)); static void union_groups PARAMS ((basic_block, basic_block));
static void set_purpose PARAMS ((tree, tree));
static rtx label_for_tag PARAMS ((unsigned));
static tree build_counter_section_fields PARAMS ((void));
static tree build_counter_section_value PARAMS ((unsigned, unsigned));
static tree build_counter_section_data_fields PARAMS ((void));
static tree build_counter_section_data_value PARAMS ((unsigned, unsigned));
static tree build_function_info_fields PARAMS ((void));
static tree build_function_info_value PARAMS ((struct function_list *));
static tree build_gcov_info_fields PARAMS ((tree));
static tree build_gcov_info_value PARAMS ((void));
/* Add edge instrumentation code to the entire insn chain. /* Add edge instrumentation code to the entire insn chain.
...@@ -170,6 +182,7 @@ instrument_edges (el) ...@@ -170,6 +182,7 @@ instrument_edges (el)
int num_instr_edges = 0; int num_instr_edges = 0;
int num_edges = NUM_EDGES (el); int num_edges = NUM_EDGES (el);
basic_block bb; basic_block bb;
struct section_info *section_info;
remove_fake_edges (); remove_fake_edges ();
FOR_BB_BETWEEN (bb, ENTRY_BLOCK_PTR, NULL, next_bb) FOR_BB_BETWEEN (bb, ENTRY_BLOCK_PTR, NULL, next_bb)
...@@ -194,15 +207,14 @@ instrument_edges (el) ...@@ -194,15 +207,14 @@ instrument_edges (el)
} }
} }
profile_info.count_edges_instrumented_now = num_instr_edges; section_info = find_counters_section (GCOV_TAG_ARC_COUNTS);
section_info->n_counters_now = num_instr_edges;
total_num_edges_instrumented += num_instr_edges; total_num_edges_instrumented += num_instr_edges;
profile_info.count_instrumented_edges = total_num_edges_instrumented; section_info->n_counters = total_num_edges_instrumented;
total_num_blocks_created += num_edges; total_num_blocks_created += num_edges;
if (rtl_dump_file) if (rtl_dump_file)
fprintf (rtl_dump_file, "%d edges instrumented\n", num_instr_edges); fprintf (rtl_dump_file, "%d edges instrumented\n", num_instr_edges);
commit_edge_insertions_watch_calls ();
} }
struct section_reference struct section_reference
...@@ -847,6 +859,7 @@ compute_branch_probabilities () ...@@ -847,6 +859,7 @@ compute_branch_probabilities ()
free_aux_for_blocks (); free_aux_for_blocks ();
if (exec_counts) if (exec_counts)
free (exec_counts); free (exec_counts);
find_counters_section (GCOV_TAG_ARC_COUNTS)->present = 1;
} }
/* Compute checksum for the current function. We generate a CRC32. */ /* Compute checksum for the current function. We generate a CRC32. */
...@@ -908,13 +921,18 @@ void ...@@ -908,13 +921,18 @@ void
branch_prob () branch_prob ()
{ {
basic_block bb; basic_block bb;
int i; unsigned i;
int num_edges, ignored_edges; unsigned num_edges, ignored_edges;
struct edge_list *el; struct edge_list *el;
const char *name = IDENTIFIER_POINTER const char *name = IDENTIFIER_POINTER
(DECL_ASSEMBLER_NAME (current_function_decl)); (DECL_ASSEMBLER_NAME (current_function_decl));
profile_info.current_function_cfg_checksum = compute_checksum (); profile_info.current_function_cfg_checksum = compute_checksum ();
for (i = 0; i < profile_info.n_sections; i++)
{
profile_info.section_info[i].n_counters_now = 0;
profile_info.section_info[i].present = 0;
}
if (rtl_dump_file) if (rtl_dump_file)
fprintf (rtl_dump_file, "CFG checksum is %u\n", fprintf (rtl_dump_file, "CFG checksum is %u\n",
...@@ -1082,7 +1100,7 @@ branch_prob () ...@@ -1082,7 +1100,7 @@ branch_prob ()
if (gcov_write_unsigned (bbg_file, GCOV_TAG_BLOCKS) if (gcov_write_unsigned (bbg_file, GCOV_TAG_BLOCKS)
|| !(offset = gcov_reserve_length (bbg_file))) || !(offset = gcov_reserve_length (bbg_file)))
goto bbg_error; goto bbg_error;
for (i = 0; i != n_basic_blocks + 2; i++) for (i = 0; i != (unsigned) (n_basic_blocks + 2); i++)
if (gcov_write_unsigned (bbg_file, 0)) if (gcov_write_unsigned (bbg_file, 0))
goto bbg_error; goto bbg_error;
if (gcov_write_length (bbg_file, offset)) if (gcov_write_length (bbg_file, offset))
...@@ -1118,6 +1136,7 @@ branch_prob () ...@@ -1118,6 +1136,7 @@ branch_prob ()
goto bbg_error; goto bbg_error;
} }
} }
if (gcov_write_length (bbg_file, offset)) if (gcov_write_length (bbg_file, offset))
goto bbg_error; goto bbg_error;
} }
...@@ -1184,6 +1203,7 @@ branch_prob () ...@@ -1184,6 +1203,7 @@ branch_prob ()
} }
insn = NEXT_INSN (insn); insn = NEXT_INSN (insn);
} }
if (offset) if (offset)
{ {
if (gcov_write_unsigned (bbg_file, 0) if (gcov_write_unsigned (bbg_file, 0)
...@@ -1210,6 +1230,9 @@ branch_prob () ...@@ -1210,6 +1230,9 @@ branch_prob ()
struct function_list *item; struct function_list *item;
instrument_edges (el); instrument_edges (el);
/* Commit changes done by instrumentation. */
commit_edge_insertions_watch_calls ();
allocate_reg_info (max_reg_num (), FALSE, FALSE); allocate_reg_info (max_reg_num (), FALSE, FALSE);
/* ??? Probably should re-use the existing struct function. */ /* ??? Probably should re-use the existing struct function. */
...@@ -1221,17 +1244,26 @@ branch_prob () ...@@ -1221,17 +1244,26 @@ branch_prob ()
item->next = 0; item->next = 0;
item->name = xstrdup (name); item->name = xstrdup (name);
item->cfg_checksum = profile_info.current_function_cfg_checksum; item->cfg_checksum = profile_info.current_function_cfg_checksum;
item->count_edges = profile_info.count_edges_instrumented_now; item->n_counter_sections = 0;
for (i = 0; i < profile_info.n_sections; i++)
if (profile_info.section_info[i].n_counters_now)
{
item->counter_sections[item->n_counter_sections].tag =
profile_info.section_info[i].tag;
item->counter_sections[item->n_counter_sections].n_counters =
profile_info.section_info[i].n_counters_now;
item->n_counter_sections++;
}
} }
remove_fake_edges (); remove_fake_edges ();
free_aux_for_edges ();
/* Re-merge split basic blocks and the mess introduced by /* Re-merge split basic blocks and the mess introduced by
insert_insn_on_edge. */ insert_insn_on_edge. */
cleanup_cfg (profile_arc_flag ? CLEANUP_EXPENSIVE : 0); cleanup_cfg (profile_arc_flag ? CLEANUP_EXPENSIVE : 0);
if (rtl_dump_file) if (rtl_dump_file)
dump_flow_info (rtl_dump_file); dump_flow_info (rtl_dump_file);
free_aux_for_edges ();
free_edge_list (el); free_edge_list (el);
} }
...@@ -1477,198 +1509,570 @@ end_branch_prob () ...@@ -1477,198 +1509,570 @@ end_branch_prob ()
} }
} }
/* Write out the structure which libgcc uses to locate all the arc /* Find (and create if not present) a section with TAG. */
counters. The structures used here must match those defined in struct section_info *
gcov-io.h. Write out the constructor to call __gcov_init. */ find_counters_section (tag)
unsigned tag;
{
unsigned i;
void for (i = 0; i < profile_info.n_sections; i++)
create_profiler () if (profile_info.section_info[i].tag == tag)
return profile_info.section_info + i;
if (i == MAX_COUNTER_SECTIONS)
abort ();
profile_info.section_info[i].tag = tag;
profile_info.section_info[i].present = 0;
profile_info.section_info[i].n_counters = 0;
profile_info.section_info[i].n_counters_now = 0;
profile_info.n_sections++;
return profile_info.section_info + i;
}
/* Set FIELDS as purpose to VALUE. */
static void
set_purpose (value, fields)
tree value;
tree fields;
{ {
tree fields, field, value = NULL_TREE; tree act_field, act_value;
tree ginfo_type;
tree string_type; for (act_field = fields, act_value = value;
tree gcov_type, gcov_ptr_type; act_field;
char name[20]; act_field = TREE_CHAIN (act_field), act_value = TREE_CHAIN (act_value))
char *ctor_name; TREE_PURPOSE (act_value) = act_field;
tree structure, ctor; }
rtx structure_address;
int save_flag_inline_functions = flag_inline_functions;
if (!profile_info.count_instrumented_edges) /* Returns label for base of counters inside TAG section. */
return; static rtx
label_for_tag (tag)
unsigned tag;
{
switch (tag)
{
case GCOV_TAG_ARC_COUNTS:
return profiler_label;
default:
abort ();
}
}
/* Creates fields of struct counter_section (in gcov-io.h). */
static tree
build_counter_section_fields ()
{
tree field, fields;
/* tag */
fields = build_decl (FIELD_DECL, NULL_TREE, unsigned_type_node);
/* n_counters */
field = build_decl (FIELD_DECL, NULL_TREE, unsigned_type_node);
TREE_CHAIN (field) = fields;
fields = field;
return fields;
}
/* Creates value of struct counter_section (in gcov-io.h). */
static tree
build_counter_section_value (tag, n_counters)
unsigned tag;
unsigned n_counters;
{
tree value = NULL_TREE;
/* tag */
value = tree_cons (NULL_TREE,
convert (unsigned_type_node,
build_int_2 (tag, 0)),
value);
string_type = build_pointer_type /* n_counters */
(build_qualified_type (char_type_node, TYPE_QUAL_CONST)); value = tree_cons (NULL_TREE,
convert (unsigned_type_node,
build_int_2 (n_counters, 0)),
value);
return value;
}
/* Creates fields of struct counter_section_data (in gcov-io.h). */
static tree
build_counter_section_data_fields ()
{
tree field, fields, gcov_type, gcov_ptr_type;
gcov_type = make_signed_type (GCOV_TYPE_SIZE);
gcov_ptr_type =
build_pointer_type (build_qualified_type (gcov_type,
TYPE_QUAL_CONST));
/* tag */
fields = build_decl (FIELD_DECL, NULL_TREE, unsigned_type_node);
/* n_counters */
field = build_decl (FIELD_DECL, NULL_TREE, unsigned_type_node);
TREE_CHAIN (field) = fields;
fields = field;
/* counters */
field = build_decl (FIELD_DECL, NULL_TREE, gcov_ptr_type);
TREE_CHAIN (field) = fields;
fields = field;
return fields;
}
/* Creates value of struct counter_section_data (in gcov-io.h). */
static tree
build_counter_section_data_value (tag, n_counters)
unsigned tag;
unsigned n_counters;
{
tree value = NULL_TREE, counts_table, gcov_type, gcov_ptr_type;
gcov_type = make_signed_type (GCOV_TYPE_SIZE); gcov_type = make_signed_type (GCOV_TYPE_SIZE);
gcov_ptr_type gcov_ptr_type
= build_pointer_type (build_qualified_type = build_pointer_type (build_qualified_type
(gcov_type, TYPE_QUAL_CONST)); (gcov_type, TYPE_QUAL_CONST));
/* tag */
value = tree_cons (NULL_TREE,
convert (unsigned_type_node,
build_int_2 (tag, 0)),
value);
ginfo_type = (*lang_hooks.types.make_type) (RECORD_TYPE); /* n_counters */
value = tree_cons (NULL_TREE,
convert (unsigned_type_node,
build_int_2 (n_counters, 0)),
value);
/* counters */
if (n_counters)
{
tree gcov_type_array_type =
build_array_type (gcov_type,
build_index_type (build_int_2 (n_counters - 1,
0)));
counts_table =
build (VAR_DECL, gcov_type_array_type, NULL_TREE, NULL_TREE);
TREE_STATIC (counts_table) = 1;
DECL_NAME (counts_table) = get_identifier (XSTR (label_for_tag (tag), 0));
assemble_variable (counts_table, 0, 0, 0);
counts_table = build1 (ADDR_EXPR, gcov_ptr_type, counts_table);
}
else
counts_table = null_pointer_node;
value = tree_cons (NULL_TREE, counts_table, value);
return value;
}
/* Creates fields for struct function_info type (in gcov-io.h). */
static tree
build_function_info_fields ()
{
tree field, fields, counter_section_fields, counter_section_type;
tree counter_sections_ptr_type;
tree string_type =
build_pointer_type (build_qualified_type (char_type_node,
TYPE_QUAL_CONST));
/* name */
fields = build_decl (FIELD_DECL, NULL_TREE, string_type);
/* checksum */
field = build_decl (FIELD_DECL, NULL_TREE, unsigned_type_node);
TREE_CHAIN (field) = fields;
fields = field;
/* n_counter_sections */
field = build_decl (FIELD_DECL, NULL_TREE, unsigned_type_node);
TREE_CHAIN (field) = fields;
fields = field;
/* counter_sections */
counter_section_fields = build_counter_section_fields ();
counter_section_type = (*lang_hooks.types.make_type) (RECORD_TYPE);
finish_builtin_struct (counter_section_type, "__counter_section",
counter_section_fields, NULL_TREE);
counter_sections_ptr_type =
build_pointer_type
(build_qualified_type (counter_section_type,
TYPE_QUAL_CONST));
field = build_decl (FIELD_DECL, NULL_TREE, counter_sections_ptr_type);
TREE_CHAIN (field) = fields;
fields = field;
return fields;
}
/* Creates value for struct function_info (in gcov-io.h). */
static tree
build_function_info_value (function)
struct function_list *function;
{
tree value = NULL_TREE;
size_t name_len = strlen (function->name);
tree fname = build_string (name_len + 1, function->name);
tree string_type =
build_pointer_type (build_qualified_type (char_type_node,
TYPE_QUAL_CONST));
tree counter_section_fields, counter_section_type, counter_sections_value;
tree counter_sections_ptr_type, counter_sections_array_type;
unsigned i;
/* name */
TREE_TYPE (fname) =
build_array_type (char_type_node,
build_index_type (build_int_2 (name_len, 0)));
value = tree_cons (NULL_TREE,
build1 (ADDR_EXPR,
string_type,
fname),
value);
/* checksum */
value = tree_cons (NULL_TREE,
convert (unsigned_type_node,
build_int_2 (function->cfg_checksum, 0)),
value);
/* n_counter_sections */
value = tree_cons (NULL_TREE,
convert (unsigned_type_node,
build_int_2 (function->n_counter_sections, 0)),
value);
/* counter_sections */
counter_section_fields = build_counter_section_fields ();
counter_section_type = (*lang_hooks.types.make_type) (RECORD_TYPE);
counter_sections_ptr_type =
build_pointer_type
(build_qualified_type (counter_section_type,
TYPE_QUAL_CONST));
counter_sections_array_type =
build_array_type (counter_section_type,
build_index_type (
build_int_2 (function->n_counter_sections - 1,
0)));
counter_sections_value = NULL_TREE;
for (i = 0; i < function->n_counter_sections; i++)
{
tree counter_section_value =
build_counter_section_value (function->counter_sections[i].tag,
function->counter_sections[i].n_counters);
set_purpose (counter_section_value, counter_section_fields);
counter_sections_value = tree_cons (NULL_TREE,
build (CONSTRUCTOR,
counter_section_type,
NULL_TREE,
nreverse (counter_section_value)),
counter_sections_value);
}
finish_builtin_struct (counter_section_type, "__counter_section",
counter_section_fields, NULL_TREE);
if (function->n_counter_sections)
{
counter_sections_value =
build (CONSTRUCTOR,
counter_sections_array_type,
NULL_TREE,
nreverse (counter_sections_value)),
counter_sections_value = build1 (ADDR_EXPR,
counter_sections_ptr_type,
counter_sections_value);
}
else
counter_sections_value = null_pointer_node;
value = tree_cons (NULL_TREE, counter_sections_value, value);
return value;
}
/* Creates fields of struct gcov_info type (in gcov-io.h). */
static tree
build_gcov_info_fields (gcov_info_type)
tree gcov_info_type;
{
tree field, fields;
char *filename;
int filename_len;
tree string_type =
build_pointer_type (build_qualified_type (char_type_node,
TYPE_QUAL_CONST));
tree function_info_fields, function_info_type, function_info_ptr_type;
tree counter_section_data_fields, counter_section_data_type;
tree counter_section_data_ptr_type;
/* Version ident */ /* Version ident */
fields = build_decl (FIELD_DECL, NULL_TREE, long_unsigned_type_node); fields = build_decl (FIELD_DECL, NULL_TREE, long_unsigned_type_node);
value = tree_cons (fields, convert (long_unsigned_type_node, build_int_2
(GCOV_VERSION, 0)), value); /* next -- NULL */
field = build_decl (FIELD_DECL, NULL_TREE,
/* NULL */ build_pointer_type (build_qualified_type (gcov_info_type,
field = build_decl (FIELD_DECL, NULL_TREE, build_pointer_type TYPE_QUAL_CONST)));
(build_qualified_type
(ginfo_type, TYPE_QUAL_CONST)));
TREE_CHAIN (field) = fields; TREE_CHAIN (field) = fields;
fields = field; fields = field;
value = tree_cons (fields, null_pointer_node, value);
/* Filename */ /* Filename */
{ filename = getpwd ();
tree filename_string; filename = (filename && da_file_name[0] != '/'
char *filename; ? concat (filename, "/", da_file_name, NULL)
int filename_len; : da_file_name);
filename_len = strlen (filename);
filename = getpwd (); if (filename != da_file_name)
filename = (filename && da_file_name[0] != '/' free (filename);
? concat (filename, "/", da_file_name, NULL)
: da_file_name); field = build_decl (FIELD_DECL, NULL_TREE, string_type);
filename_len = strlen (filename); TREE_CHAIN (field) = fields;
filename_string = build_string (filename_len + 1, filename); fields = field;
if (filename != da_file_name)
free (filename);
TREE_TYPE (filename_string) = build_array_type
(char_type_node, build_index_type
(build_int_2 (filename_len, 0)));
field = build_decl (FIELD_DECL, NULL_TREE, string_type);
TREE_CHAIN (field) = fields;
fields = field;
value = tree_cons (fields, build1 (ADDR_EXPR, string_type,
filename_string), value);
}
/* Workspace */ /* Workspace */
field = build_decl (FIELD_DECL, NULL_TREE, long_integer_type_node); field = build_decl (FIELD_DECL, NULL_TREE, long_integer_type_node);
TREE_CHAIN (field) = fields; TREE_CHAIN (field) = fields;
fields = field; fields = field;
value = tree_cons (fields,
convert (long_integer_type_node, integer_zero_node), /* number of functions */
value); field = build_decl (FIELD_DECL, NULL_TREE, unsigned_type_node);
TREE_CHAIN (field) = fields;
fields = field;
/* function_info table */ /* function_info table */
{ function_info_fields = build_function_info_fields ();
struct function_list *item; function_info_type = (*lang_hooks.types.make_type) (RECORD_TYPE);
int num_nodes = 0; finish_builtin_struct (function_info_type, "__function_info",
tree array_value = NULL_TREE; function_info_fields, NULL_TREE);
tree finfo_type, finfo_ptr_type; function_info_ptr_type =
tree name, checksum, arcs; build_pointer_type
(build_qualified_type (function_info_type,
finfo_type = (*lang_hooks.types.make_type) (RECORD_TYPE); TYPE_QUAL_CONST));
name = build_decl (FIELD_DECL, NULL_TREE, string_type); field = build_decl (FIELD_DECL, NULL_TREE, function_info_ptr_type);
checksum = build_decl (FIELD_DECL, NULL_TREE, unsigned_type_node); TREE_CHAIN (field) = fields;
TREE_CHAIN (checksum) = name; fields = field;
arcs = build_decl (FIELD_DECL, NULL_TREE, unsigned_type_node);
TREE_CHAIN (arcs) = checksum;
finish_builtin_struct (finfo_type, "__function_info",
arcs, NULL_TREE);
finfo_ptr_type = build_pointer_type
(build_qualified_type (finfo_type, TYPE_QUAL_CONST));
for (item = functions_head; item != 0; item = item->next, num_nodes++)
{
size_t name_len = strlen (item->name);
tree finfo_value = NULL_TREE;
tree fname = build_string (name_len + 1, item->name);
TREE_TYPE (fname) = build_array_type
(char_type_node, build_index_type (build_int_2 (name_len, 0)));
finfo_value = tree_cons (name, build1
(ADDR_EXPR, string_type,
fname), finfo_value);
finfo_value = tree_cons (checksum, convert
(unsigned_type_node,
build_int_2 (item->cfg_checksum, 0)),
finfo_value);
finfo_value = tree_cons (arcs, convert
(unsigned_type_node,
build_int_2 (item->count_edges, 0)),
finfo_value);
array_value = tree_cons (NULL_TREE, build
(CONSTRUCTOR, finfo_type, NULL_TREE,
nreverse (finfo_value)), array_value);
}
/* Create constructor for array. */
if (num_nodes)
{
tree array_type;
array_type = build_array_type (finfo_type, build_index_type
(build_int_2 (num_nodes - 1, 0)));
array_value = build (CONSTRUCTOR, array_type,
NULL_TREE, nreverse (array_value));
array_value = build1
(ADDR_EXPR, finfo_ptr_type, array_value);
}
else
array_value = null_pointer_node;
field = build_decl (FIELD_DECL, NULL_TREE, finfo_ptr_type);
TREE_CHAIN (field) = fields;
fields = field;
value = tree_cons (fields, array_value, value);
/* number of functions */
field = build_decl (FIELD_DECL, NULL_TREE, unsigned_type_node);
TREE_CHAIN (field) = fields;
fields = field;
value = tree_cons (fields, convert (unsigned_type_node, build_int_2
(num_nodes, 0)), value);
}
/* arc count table */
{
tree counts_table = null_pointer_node;
if (profile_info.count_instrumented_edges)
{
tree gcov_type_array_type
= build_array_type (gcov_type, build_index_type
(build_int_2 (profile_info.
count_instrumented_edges - 1, 0)));
/* No values. */
counts_table
= build (VAR_DECL, gcov_type_array_type, NULL_TREE, NULL_TREE);
TREE_STATIC (counts_table) = 1;
DECL_NAME (counts_table) = get_identifier (XSTR (profiler_label, 0));
assemble_variable (counts_table, 0, 0, 0);
counts_table = build1 (ADDR_EXPR, gcov_ptr_type, counts_table);
}
field = build_decl (FIELD_DECL, NULL_TREE, gcov_ptr_type); /* n_counter_sections */
TREE_CHAIN (field) = fields;
fields = field;
value = tree_cons (fields, counts_table, value);
}
/* number of arc counts */
field = build_decl (FIELD_DECL, NULL_TREE, unsigned_type_node); field = build_decl (FIELD_DECL, NULL_TREE, unsigned_type_node);
TREE_CHAIN (field) = fields; TREE_CHAIN (field) = fields;
fields = field; fields = field;
value = tree_cons (fields, convert
(unsigned_type_node, /* counter sections */
build_int_2 (profile_info counter_section_data_fields = build_counter_section_data_fields ();
.count_instrumented_edges, 0)), counter_section_data_type = (*lang_hooks.types.make_type) (RECORD_TYPE);
finish_builtin_struct (counter_section_data_type, "__counter_section_data",
counter_section_data_fields, NULL_TREE);
counter_section_data_ptr_type =
build_pointer_type
(build_qualified_type (counter_section_data_type,
TYPE_QUAL_CONST));
field = build_decl (FIELD_DECL, NULL_TREE, counter_section_data_ptr_type);
TREE_CHAIN (field) = fields;
fields = field;
return fields;
}
/* Creates struct gcov_info value (in gcov-io.h). */
static tree
build_gcov_info_value ()
{
tree value = NULL_TREE;
tree filename_string;
char *filename;
int filename_len;
unsigned n_functions, i;
struct function_list *item;
tree string_type =
build_pointer_type (build_qualified_type (char_type_node,
TYPE_QUAL_CONST));
tree function_info_fields, function_info_type, function_info_ptr_type;
tree functions;
tree counter_section_data_fields, counter_section_data_type;
tree counter_section_data_ptr_type, counter_sections;
/* Version ident */
value = tree_cons (NULL_TREE,
convert (long_unsigned_type_node,
build_int_2 (GCOV_VERSION, 0)),
value);
/* next -- NULL */
value = tree_cons (NULL_TREE, null_pointer_node, value);
/* Filename */
filename = getpwd ();
filename = (filename && da_file_name[0] != '/'
? concat (filename, "/", da_file_name, NULL)
: da_file_name);
filename_len = strlen (filename);
filename_string = build_string (filename_len + 1, filename);
if (filename != da_file_name)
free (filename);
TREE_TYPE (filename_string) =
build_array_type (char_type_node,
build_index_type (build_int_2 (filename_len, 0)));
value = tree_cons (NULL_TREE,
build1 (ADDR_EXPR,
string_type,
filename_string),
value);
/* Workspace */
value = tree_cons (NULL_TREE,
convert (long_integer_type_node, integer_zero_node),
value);
/* number of functions */
n_functions = 0;
for (item = functions_head; item != 0; item = item->next, n_functions++)
continue;
value = tree_cons (NULL_TREE,
convert (unsigned_type_node,
build_int_2 (n_functions, 0)),
value); value);
/* function_info table */
function_info_fields = build_function_info_fields ();
function_info_type = (*lang_hooks.types.make_type) (RECORD_TYPE);
function_info_ptr_type =
build_pointer_type (
build_qualified_type (function_info_type,
TYPE_QUAL_CONST));
functions = NULL_TREE;
for (item = functions_head; item != 0; item = item->next)
{
tree function_info_value = build_function_info_value (item);
set_purpose (function_info_value, function_info_fields);
functions = tree_cons (NULL_TREE,
build (CONSTRUCTOR,
function_info_type,
NULL_TREE,
nreverse (function_info_value)),
functions);
}
finish_builtin_struct (function_info_type, "__function_info",
function_info_fields, NULL_TREE);
/* Create constructor for array. */
if (n_functions)
{
tree array_type;
array_type = build_array_type (
function_info_type,
build_index_type (build_int_2 (n_functions - 1, 0)));
functions = build (CONSTRUCTOR,
array_type,
NULL_TREE,
nreverse (functions));
functions = build1 (ADDR_EXPR,
function_info_ptr_type,
functions);
}
else
functions = null_pointer_node;
value = tree_cons (NULL_TREE, functions, value);
/* n_counter_sections */
value = tree_cons (NULL_TREE,
convert (unsigned_type_node,
build_int_2 (profile_info.n_sections, 0)),
value);
/* counter sections */
counter_section_data_fields = build_counter_section_data_fields ();
counter_section_data_type = (*lang_hooks.types.make_type) (RECORD_TYPE);
counter_sections = NULL_TREE;
for (i = 0; i < profile_info.n_sections; i++)
{
tree counter_sections_value =
build_counter_section_data_value (
profile_info.section_info[i].tag,
profile_info.section_info[i].n_counters);
set_purpose (counter_sections_value, counter_section_data_fields);
counter_sections = tree_cons (NULL_TREE,
build (CONSTRUCTOR,
counter_section_data_type,
NULL_TREE,
nreverse (counter_sections_value)),
counter_sections);
}
finish_builtin_struct (counter_section_data_type, "__counter_section_data",
counter_section_data_fields, NULL_TREE);
counter_section_data_ptr_type =
build_pointer_type
(build_qualified_type (counter_section_data_type,
TYPE_QUAL_CONST));
if (profile_info.n_sections)
{
counter_sections =
build (CONSTRUCTOR,
build_array_type (
counter_section_data_type,
build_index_type (build_int_2 (profile_info.n_sections - 1, 0))),
NULL_TREE,
nreverse (counter_sections));
counter_sections = build1 (ADDR_EXPR,
counter_section_data_ptr_type,
counter_sections);
}
else
counter_sections = null_pointer_node;
value = tree_cons (NULL_TREE, counter_sections, value);
return value;
}
/* Write out the structure which libgcc uses to locate all the arc
counters. The structures used here must match those defined in
gcov-io.h. Write out the constructor to call __gcov_init. */
void
create_profiler ()
{
tree gcov_info_fields, gcov_info_type, gcov_info_value, gcov_info;
char name[20];
char *ctor_name;
tree ctor;
rtx gcov_info_address;
int save_flag_inline_functions = flag_inline_functions;
unsigned i;
for (i = 0; i < profile_info.n_sections; i++)
if (profile_info.section_info[i].n_counters_now)
break;
if (i == profile_info.n_sections)
return;
finish_builtin_struct (ginfo_type, "__gcov_info", fields, NULL_TREE); gcov_info_type = (*lang_hooks.types.make_type) (RECORD_TYPE);
structure = build (VAR_DECL, ginfo_type, NULL_TREE, NULL_TREE); gcov_info_fields = build_gcov_info_fields (gcov_info_type);
DECL_INITIAL (structure) gcov_info_value = build_gcov_info_value ();
= build (CONSTRUCTOR, ginfo_type, NULL_TREE, nreverse (value)); set_purpose (gcov_info_value, gcov_info_fields);
TREE_STATIC (structure) = 1; finish_builtin_struct (gcov_info_type, "__gcov_info",
gcov_info_fields, NULL_TREE);
gcov_info = build (VAR_DECL, gcov_info_type, NULL_TREE, NULL_TREE);
DECL_INITIAL (gcov_info) =
build (CONSTRUCTOR, gcov_info_type, NULL_TREE,
nreverse (gcov_info_value));
TREE_STATIC (gcov_info) = 1;
ASM_GENERATE_INTERNAL_LABEL (name, "LPBX", 0); ASM_GENERATE_INTERNAL_LABEL (name, "LPBX", 0);
DECL_NAME (structure) = get_identifier (name); DECL_NAME (gcov_info) = get_identifier (name);
/* Build structure. */ /* Build structure. */
assemble_variable (structure, 0, 0, 0); assemble_variable (gcov_info, 0, 0, 0);
/* Build the constructor function to invoke __gcov_init. */ /* Build the constructor function to invoke __gcov_init. */
ctor_name = concat (IDENTIFIER_POINTER (get_file_function_name ('I')), ctor_name = concat (IDENTIFIER_POINTER (get_file_function_name ('I')),
...@@ -1696,12 +2100,14 @@ create_profiler () ...@@ -1696,12 +2100,14 @@ create_profiler ()
cfun->arc_profile = 0; cfun->arc_profile = 0;
/* Actually generate the code to call __gcov_init. */ /* Actually generate the code to call __gcov_init. */
structure_address = force_reg (Pmode, gen_rtx_SYMBOL_REF gcov_info_address = force_reg (Pmode,
(Pmode, IDENTIFIER_POINTER gen_rtx_SYMBOL_REF (
(DECL_NAME (structure)))); Pmode,
IDENTIFIER_POINTER (
DECL_NAME (gcov_info))));
emit_library_call (gen_rtx_SYMBOL_REF (Pmode, "__gcov_init"), emit_library_call (gen_rtx_SYMBOL_REF (Pmode, "__gcov_init"),
LCT_NORMAL, VOIDmode, 1, LCT_NORMAL, VOIDmode, 1,
structure_address, Pmode); gcov_info_address, Pmode);
expand_function_end (input_filename, lineno, 0); expand_function_end (input_filename, lineno, 0);
(*lang_hooks.decls.poplevel) (1, 0, 1); (*lang_hooks.decls.poplevel) (1, 0, 1);
......
...@@ -21,18 +21,25 @@ Software Foundation, 59 Temple Place - Suite 330, Boston, MA ...@@ -21,18 +21,25 @@ Software Foundation, 59 Temple Place - Suite 330, Boston, MA
#ifndef GCC_PROFILE_H #ifndef GCC_PROFILE_H
#define GCC_PROFILE_H #define GCC_PROFILE_H
/* The number of different counter sections. */
#define MAX_COUNTER_SECTIONS 1
/* Info about number of counters in the section. */
struct section_info
{
unsigned tag; /* Section tag. */
int present; /* Are the data from this section read into gcc? */
int n_counters; /* Total number of counters. */
int n_counters_now; /* Number of counters in the current function. */
};
struct profile_info struct profile_info
{ {
/* Used by final, for allocating the proper amount of storage for the /* Information about numbers of counters in counter sections, for
instrumented arc execution counts. */ allocating the storage and storing the sizes. */
unsigned n_sections;
int count_instrumented_edges; struct section_info section_info[MAX_COUNTER_SECTIONS];
/* Used by final, for writing correct # of instrumented edges
in this function. */
int count_edges_instrumented_now;
/* Checksum of the cfg. Used for 'identification' of code. /* Checksum of the cfg. Used for 'identification' of code.
Used by final. */ Used by final. */
...@@ -46,9 +53,10 @@ struct profile_info ...@@ -46,9 +53,10 @@ struct profile_info
/* The number of profiles merged to form the profile data for the current /* The number of profiles merged to form the profile data for the current
function. */ function. */
int count_profiles_merged; int count_profiles_merged;
}; };
extern struct profile_info profile_info; extern struct profile_info profile_info;
struct section_info *find_counters_section PARAMS ((unsigned));
#endif #endif
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment