diff options
-rw-r--r-- | gcc/ChangeLog | 28 | ||||
-rw-r--r-- | gcc/gcov-dump.c | 2 | ||||
-rw-r--r-- | gcc/gcov-io.h | 28 | ||||
-rw-r--r-- | gcc/libgcov.c | 142 | ||||
-rw-r--r-- | gcc/profile.c | 754 | ||||
-rw-r--r-- | gcc/profile.h | 30 |
6 files changed, 745 insertions, 239 deletions
diff --git a/gcc/ChangeLog b/gcc/ChangeLog index 2aebbd0..fb5ca7e 100644 --- a/gcc/ChangeLog +++ b/gcc/ChangeLog @@ -1,3 +1,31 @@ +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> * pa.c (compute_frame_size): Don't assume PREFERRED_STACK_BOUNDARY diff --git a/gcc/gcov-dump.c b/gcc/gcov-dump.c index 4da0591..acea56d 100644 --- a/gcc/gcov-dump.c +++ b/gcc/gcov-dump.c @@ -131,7 +131,7 @@ print_prefix (filename, depth) { static const char prefix[] = " "; - printf ("%s:%.*s", filename, depth, prefix); + printf ("%s:%.*s", filename, (int) depth, prefix); } static void diff --git a/gcc/gcov-io.h b/gcc/gcov-io.h index 6976bc3..ce29f67 100644 --- a/gcc/gcov-io.h +++ b/gcc/gcov-io.h @@ -216,16 +216,33 @@ struct gcov_summary gcov_type arc_sum_max; /* sum of max_one */ }; -#if IN_LIBGCC2 /* Structures embedded in coveraged program. The structures generated 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. */ struct function_info { const char *name; /* (mangled) name of function */ 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. */ @@ -237,11 +254,12 @@ struct gcov_info const char *filename; /* output file name */ long wkspc; /* libgcc workspace */ - const struct function_info *functions; /* table 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_arc_counts; /* number of arc counts */ + unsigned n_counter_sections; /* Number of types of counters */ + const struct counter_section_data *counter_sections; + /* The data to be put into the sections. */ }; /* Register a new object file module. */ diff --git a/gcc/libgcov.c b/gcc/libgcov.c index 57bfb26..657de36 100644 --- a/gcc/libgcov.c +++ b/gcc/libgcov.c @@ -112,14 +112,35 @@ gcov_exit (void) int merging = 0; long base; const struct function_info *fn_info; + gcov_type **counters; gcov_type *count_ptr; 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; if (!ptr->filename) 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++; @@ -155,7 +176,6 @@ gcov_exit (void) if (merging) { /* Merge data from file. */ - unsigned tag, length; if (gcov_read_unsigned (da_file, &tag) || tag != GCOV_DATA_MAGIC) { @@ -173,7 +193,6 @@ gcov_exit (void) } /* Merge execution counts for each function. */ - count_ptr = ptr->arc_counts; for (ix = ptr->n_functions, fn_info = ptr->functions; ix--; fn_info++) { @@ -194,33 +213,40 @@ gcov_exit (void) ptr->filename, fn_info->name); goto read_fatal; } - { - unsigned flength, checksum; - - if (gcov_read_unsigned (da_file, &flength) - || 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)) + + if (gcov_read_unsigned (da_file, &flength) + || gcov_skip_string (da_file, flength) + || gcov_read_unsigned (da_file, &checksum)) goto read_error; - if (tag != GCOV_TAG_ARC_COUNTS - || length / 8 != fn_info->n_arc_counts) + if (flength != strlen (fn_info->name) + || checksum != fn_info->checksum) goto read_mismatch; - { - gcov_type count; - - for (jx = fn_info->n_arc_counts; jx--; count_ptr++) - if (gcov_read_counter (da_file, &count)) + + /* Counters. */ + for (f_sect_index = 0; + f_sect_index < fn_info->n_counter_sections; + f_sect_index++) + { + if (gcov_read_unsigned (da_file, &tag) + || gcov_read_unsigned (da_file, &length)) goto read_error; - else - *count_ptr += count; - } + for (sect_index = 0; + 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 */ @@ -279,7 +305,7 @@ gcov_exit (void) } object.runs++; - object.arcs = ptr->n_arc_counts; + object.arcs = ptr->counter_sections[arc_data_index].n_counters; object.arc_sum = 0; if (object.arc_max_one < object_max_one) object.arc_max_one = object_max_one; @@ -299,7 +325,8 @@ gcov_exit (void) } /* 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++) { /* Announce function. */ @@ -312,24 +339,41 @@ gcov_exit (void) || gcov_write_unsigned (da_file, fn_info->checksum) || gcov_write_length (da_file, base)) goto write_error; - - /* arc counts. */ - if (gcov_write_unsigned (da_file, GCOV_TAG_ARC_COUNTS) - || !(base = gcov_reserve_length (da_file))) - goto write_error; - - for (jx = fn_info->n_arc_counts; jx--;) + + /* counters. */ + for (f_sect_index = 0; + f_sect_index < fn_info->n_counter_sections; + f_sect_index++) { - 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 (object.arc_max_sum < count) - object.arc_max_sum = count; - if (gcov_write_counter (da_file, count)) - goto write_error; /* RIP Edsger Dijkstra */ + if (tag == GCOV_TAG_ARC_COUNTS) + { + object.arc_sum += count; + if (object.arc_max_sum < count) + 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. */ @@ -367,11 +411,12 @@ gcov_exit (void) } else { - program_arcs += ptr->n_arc_counts; + program_arcs += ptr->counter_sections[arc_data_index].n_counters; program_sum += object.arc_sum; if (program_max_sum < object.arc_max_sum) program_max_sum = object.arc_max_sum; } + free(counters); } /* Generate whole program statistics. */ @@ -465,9 +510,10 @@ __gcov_flush (void) gcov_exit (); for (ptr = gcov_list; ptr; ptr = ptr->next) { - unsigned i; + unsigned i, j; - for (i = ptr->n_arc_counts; i--;) - ptr->arc_counts[i] = 0; + for (j = 0; j < ptr->n_counter_sections; j++) + for (i = ptr->counter_sections[j].n_counters; i--;) + ptr->counter_sections[j].counters[i] = 0; } } diff --git a/gcc/profile.c b/gcc/profile.c index de2d309..261bfd0 100644 --- a/gcc/profile.c +++ b/gcc/profile.c @@ -96,7 +96,9 @@ struct function_list struct function_list *next; /* next function */ const char *name; /* function name */ 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; @@ -156,6 +158,16 @@ static gcov_type * get_exec_counts PARAMS ((void)); static unsigned compute_checksum PARAMS ((void)); static basic_block find_group PARAMS ((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. @@ -170,6 +182,7 @@ instrument_edges (el) int num_instr_edges = 0; int num_edges = NUM_EDGES (el); basic_block bb; + struct section_info *section_info; remove_fake_edges (); FOR_BB_BETWEEN (bb, ENTRY_BLOCK_PTR, NULL, next_bb) @@ -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; - profile_info.count_instrumented_edges = total_num_edges_instrumented; + section_info->n_counters = total_num_edges_instrumented; total_num_blocks_created += num_edges; if (rtl_dump_file) fprintf (rtl_dump_file, "%d edges instrumented\n", num_instr_edges); - - commit_edge_insertions_watch_calls (); } struct section_reference @@ -847,6 +859,7 @@ compute_branch_probabilities () free_aux_for_blocks (); if (exec_counts) free (exec_counts); + find_counters_section (GCOV_TAG_ARC_COUNTS)->present = 1; } /* Compute checksum for the current function. We generate a CRC32. */ @@ -908,13 +921,18 @@ void branch_prob () { basic_block bb; - int i; - int num_edges, ignored_edges; + unsigned i; + unsigned num_edges, ignored_edges; struct edge_list *el; const char *name = IDENTIFIER_POINTER (DECL_ASSEMBLER_NAME (current_function_decl)); 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) fprintf (rtl_dump_file, "CFG checksum is %u\n", @@ -1082,7 +1100,7 @@ branch_prob () if (gcov_write_unsigned (bbg_file, GCOV_TAG_BLOCKS) || !(offset = gcov_reserve_length (bbg_file))) 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)) goto bbg_error; if (gcov_write_length (bbg_file, offset)) @@ -1118,6 +1136,7 @@ branch_prob () goto bbg_error; } } + if (gcov_write_length (bbg_file, offset)) goto bbg_error; } @@ -1184,6 +1203,7 @@ branch_prob () } insn = NEXT_INSN (insn); } + if (offset) { if (gcov_write_unsigned (bbg_file, 0) @@ -1210,6 +1230,9 @@ branch_prob () struct function_list *item; instrument_edges (el); + + /* Commit changes done by instrumentation. */ + commit_edge_insertions_watch_calls (); allocate_reg_info (max_reg_num (), FALSE, FALSE); /* ??? Probably should re-use the existing struct function. */ @@ -1221,17 +1244,26 @@ branch_prob () item->next = 0; item->name = xstrdup (name); 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 (); + free_aux_for_edges (); /* Re-merge split basic blocks and the mess introduced by insert_insn_on_edge. */ cleanup_cfg (profile_arc_flag ? CLEANUP_EXPENSIVE : 0); if (rtl_dump_file) dump_flow_info (rtl_dump_file); - free_aux_for_edges (); free_edge_list (el); } @@ -1477,198 +1509,570 @@ end_branch_prob () } } -/* 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. */ +/* Find (and create if not present) a section with TAG. */ +struct section_info * +find_counters_section (tag) + unsigned tag; +{ + unsigned i; -void -create_profiler () + for (i = 0; i < profile_info.n_sections; i++) + 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 ginfo_type; - tree string_type; - tree gcov_type, gcov_ptr_type; - char name[20]; - char *ctor_name; - tree structure, ctor; - rtx structure_address; - int save_flag_inline_functions = flag_inline_functions; + tree act_field, act_value; + + for (act_field = fields, act_value = value; + act_field; + act_field = TREE_CHAIN (act_field), act_value = TREE_CHAIN (act_value)) + TREE_PURPOSE (act_value) = act_field; +} - if (!profile_info.count_instrumented_edges) - return; +/* Returns label for base of counters inside TAG section. */ +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 - (build_qualified_type (char_type_node, TYPE_QUAL_CONST)); + /* n_counters */ + 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_ptr_type = build_pointer_type (build_qualified_type (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 */ 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); - - /* NULL */ - field = build_decl (FIELD_DECL, NULL_TREE, build_pointer_type - (build_qualified_type - (ginfo_type, TYPE_QUAL_CONST))); + + /* next -- NULL */ + field = build_decl (FIELD_DECL, NULL_TREE, + build_pointer_type (build_qualified_type (gcov_info_type, + TYPE_QUAL_CONST))); TREE_CHAIN (field) = fields; fields = field; - value = tree_cons (fields, null_pointer_node, value); /* Filename */ - { - tree filename_string; - char *filename; - int filename_len; - - 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))); - - 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); - } + filename = getpwd (); + filename = (filename && da_file_name[0] != '/' + ? concat (filename, "/", da_file_name, NULL) + : da_file_name); + filename_len = strlen (filename); + if (filename != da_file_name) + free (filename); + + field = build_decl (FIELD_DECL, NULL_TREE, string_type); + TREE_CHAIN (field) = fields; + fields = field; /* Workspace */ field = build_decl (FIELD_DECL, NULL_TREE, long_integer_type_node); TREE_CHAIN (field) = fields; fields = field; - value = tree_cons (fields, - convert (long_integer_type_node, integer_zero_node), - value); + + /* number of functions */ + field = build_decl (FIELD_DECL, NULL_TREE, unsigned_type_node); + TREE_CHAIN (field) = fields; + fields = field; /* function_info table */ - { - struct function_list *item; - int num_nodes = 0; - tree array_value = NULL_TREE; - tree finfo_type, finfo_ptr_type; - tree name, checksum, arcs; - - finfo_type = (*lang_hooks.types.make_type) (RECORD_TYPE); - name = build_decl (FIELD_DECL, NULL_TREE, string_type); - checksum = build_decl (FIELD_DECL, NULL_TREE, unsigned_type_node); - TREE_CHAIN (checksum) = name; - 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); - } + function_info_fields = build_function_info_fields (); + function_info_type = (*lang_hooks.types.make_type) (RECORD_TYPE); + finish_builtin_struct (function_info_type, "__function_info", + function_info_fields, NULL_TREE); + function_info_ptr_type = + build_pointer_type + (build_qualified_type (function_info_type, + TYPE_QUAL_CONST)); + field = build_decl (FIELD_DECL, NULL_TREE, function_info_ptr_type); + TREE_CHAIN (field) = fields; + fields = field; - field = build_decl (FIELD_DECL, NULL_TREE, gcov_ptr_type); - TREE_CHAIN (field) = fields; - fields = field; - value = tree_cons (fields, counts_table, value); - } - - /* number of arc counts */ + /* n_counter_sections */ 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 (profile_info - .count_instrumented_edges, 0)), + + /* counter sections */ + counter_section_data_fields = build_counter_section_data_fields (); + 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); + + /* 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); - structure = build (VAR_DECL, ginfo_type, NULL_TREE, NULL_TREE); - DECL_INITIAL (structure) - = build (CONSTRUCTOR, ginfo_type, NULL_TREE, nreverse (value)); - TREE_STATIC (structure) = 1; + gcov_info_type = (*lang_hooks.types.make_type) (RECORD_TYPE); + gcov_info_fields = build_gcov_info_fields (gcov_info_type); + gcov_info_value = build_gcov_info_value (); + set_purpose (gcov_info_value, gcov_info_fields); + 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); - DECL_NAME (structure) = get_identifier (name); + DECL_NAME (gcov_info) = get_identifier (name); /* Build structure. */ - assemble_variable (structure, 0, 0, 0); + assemble_variable (gcov_info, 0, 0, 0); /* Build the constructor function to invoke __gcov_init. */ ctor_name = concat (IDENTIFIER_POINTER (get_file_function_name ('I')), @@ -1696,12 +2100,14 @@ create_profiler () cfun->arc_profile = 0; /* Actually generate the code to call __gcov_init. */ - structure_address = force_reg (Pmode, gen_rtx_SYMBOL_REF - (Pmode, IDENTIFIER_POINTER - (DECL_NAME (structure)))); + gcov_info_address = force_reg (Pmode, + gen_rtx_SYMBOL_REF ( + Pmode, + IDENTIFIER_POINTER ( + DECL_NAME (gcov_info)))); emit_library_call (gen_rtx_SYMBOL_REF (Pmode, "__gcov_init"), LCT_NORMAL, VOIDmode, 1, - structure_address, Pmode); + gcov_info_address, Pmode); expand_function_end (input_filename, lineno, 0); (*lang_hooks.decls.poplevel) (1, 0, 1); diff --git a/gcc/profile.h b/gcc/profile.h index 4b7ac56..5d681e8 100644 --- a/gcc/profile.h +++ b/gcc/profile.h @@ -21,18 +21,25 @@ Software Foundation, 59 Temple Place - Suite 330, Boston, MA #ifndef 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 { - /* Used by final, for allocating the proper amount of storage for the - instrumented arc execution counts. */ - - int count_instrumented_edges; - - /* Used by final, for writing correct # of instrumented edges - in this function. */ - - int count_edges_instrumented_now; - + /* Information about numbers of counters in counter sections, for + allocating the storage and storing the sizes. */ + unsigned n_sections; + struct section_info section_info[MAX_COUNTER_SECTIONS]; + /* Checksum of the cfg. Used for 'identification' of code. Used by final. */ @@ -46,9 +53,10 @@ struct profile_info /* The number of profiles merged to form the profile data for the current function. */ int count_profiles_merged; - }; extern struct profile_info profile_info; +struct section_info *find_counters_section PARAMS ((unsigned)); + #endif |