diff options
author | hubicka <hubicka@138bc75d-0d04-0410-961f-82ee72b054a4> | 2002-05-09 12:54:19 +0000 |
---|---|---|
committer | hubicka <hubicka@138bc75d-0d04-0410-961f-82ee72b054a4> | 2002-05-09 12:54:19 +0000 |
commit | 90c2be4439c656f63074408d6c91442511a9e061 (patch) | |
tree | da04474c0297ae3c91b3bdce0c519ca2f9d2e5a8 /gcc/final.c | |
parent | 40734805198ef874623eb7be9ec3de9251c799b7 (diff) | |
download | gcc-90c2be4439c656f63074408d6c91442511a9e061.tar.gz |
* final.c (end_final): Use C trees to output data structures for profiling.
* Makefile.in (LIBGCC_DEPS): Added missing dependency on gcov-io.h
(profile.o): New dependency profile.h
(final.o): New dependency profile.h
* profile.h: New file. New global structure profile_info.
* final.h (count_edges_instrumented_now): Declare.
(current_function_cfg_checksum): Declare.
(function_list): New structure.
(functions_head, functions_tail): New static variables.
(end_final): Emits more data, removed some -ax stuff.
(final): Stores function names and chcksums.
* gcov-io.h (__write_gcov_string): New function.
(__read_gcov_string): New function.
* gcov.c (read_profile): New function.
(create_program_flow_graph): Uses read_profile instead of reading
da_file.
(read_files): Removed da_file checking, it's done by read_profile now.
* libgcc2.c (bb_function_info): New structure.
(bb): New field in structure, removed some -ax stuff.
(__bb_exit_func): Changed structure of da_file.
* profile.c (count_edges_instrumented_now): New global variable.
(current_function_cfg_checksum): New global variable.
(max_counter_in_program): New global variable.
(get_exec_counts): New function.
(compute_checksum): New function.
(instrument_edges): Sets count_edges_instrumented_now.
(compute_branch_probabilities): Uses get_exec_counts instead of
reading da_file.
(branch_prob): Calls compute_checksum and writes extra data to bbg_file.
(init_branch_prob): Removed da_file checking, done in get_exec_counts
now.
(end_branch_prob): Removed da_file checking, done in get_exec_counts
now.
* gcov.texi: Updated information about gcov file format.
git-svn-id: svn+ssh://gcc.gnu.org/svn/gcc/trunk@53326 138bc75d-0d04-0410-961f-82ee72b054a4
Diffstat (limited to 'gcc/final.c')
-rw-r--r-- | gcc/final.c | 383 |
1 files changed, 275 insertions, 108 deletions
diff --git a/gcc/final.c b/gcc/final.c index a0adcbe70b4..57e94e78e4f 100644 --- a/gcc/final.c +++ b/gcc/final.c @@ -68,6 +68,7 @@ Software Foundation, 59 Temple Place - Suite 330, Boston, MA #include "target.h" #include "debug.h" #include "expr.h" +#include "profile.h" #ifdef XCOFF_DEBUGGING_INFO #include "xcoffout.h" /* Needed for external data @@ -114,9 +115,6 @@ static int high_function_linenum; /* Filename of last NOTE. */ static const char *last_filename; -/* Number of instrumented arcs when profile_arc_flag is set. */ -extern int count_instrumented_edges; - extern int length_unit_log; /* This is defined in insn-attrtab.c. */ /* Nonzero while outputting an `asm' with operands. @@ -198,6 +196,17 @@ static char *line_note_exists; rtx current_insn_predicate; #endif +struct function_list +{ + struct function_list *next; /* next function */ + const char *name; /* function name */ + long cfg_checksum; /* function checksum */ + long count_edges; /* number of intrumented edges in this function */ +}; + +static struct function_list *functions_head = 0; +static struct function_list **functions_tail = &functions_head; + #ifdef HAVE_ATTR_length static int asm_insn_count PARAMS ((rtx)); #endif @@ -237,7 +246,7 @@ init_final (filename) } /* Called at end of source file, - to output the block-profiling table for this entire compilation. */ + to output the arc-profiling table for this entire compilation. */ void end_final (filename) @@ -246,128 +255,268 @@ end_final (filename) if (profile_arc_flag) { char name[20]; - int align = exact_log2 (BIGGEST_ALIGNMENT / BITS_PER_UNIT); - int size, rounded; - int long_bytes = LONG_TYPE_SIZE / BITS_PER_UNIT; - int gcov_type_bytes = GCOV_TYPE_SIZE / BITS_PER_UNIT; - int pointer_bytes = POINTER_SIZE / BITS_PER_UNIT; - unsigned int align2 = LONG_TYPE_SIZE; - - size = gcov_type_bytes * count_instrumented_edges; - rounded = size; - - rounded += (BIGGEST_ALIGNMENT / BITS_PER_UNIT) - 1; - rounded = (rounded / (BIGGEST_ALIGNMENT / BITS_PER_UNIT) - * (BIGGEST_ALIGNMENT / BITS_PER_UNIT)); - - /* ??? This _really_ ought to be done with a structure layout - and with assemble_constructor. If long_bytes != pointer_bytes - we'll be emitting unaligned data at some point. */ - if (long_bytes != pointer_bytes) - abort (); - - data_section (); - - /* Output the main header, of 11 words: - 0: 1 if this file is initialized, else 0. - 1: address of file name (LPBX1). - 2: address of table of counts (LPBX2). - 3: number of counts in the table. - 4: always 0, for compatibility with Sun. + tree string_type, string_cst; + tree structure_decl, structure_value, structure_pointer_type; + tree field_decl, decl_chain, value_chain; + tree nwords_field_value, domain_type; + + /* Build types. */ + string_type = build_pointer_type (char_type_node); + + /* Libgcc2 bb structure. */ + structure_decl = make_node (RECORD_TYPE); + TYPE_PACKED (structure_decl) = flag_pack_struct; + structure_pointer_type = build_pointer_type (structure_decl); + + /* Output the main header, of 7 words: + 0: 1 if this file is initialized, else 0. + 1: address of file name (LPBX1). + 2: address of table of counts (LPBX2). + 3: number of counts in the table. + 4: always 0, libgcc2 uses this as a pointer to next ``struct bb'' The following are GNU extensions: - 5: address of table of start addrs of basic blocks (LPBX3). - 6: Number of bytes in this header. - 7: address of table of function names (LPBX4). - 8: address of table of line numbers (LPBX5) or 0. - 9: address of table of file names (LPBX6) or 0. - 10: space reserved for basic block profiling. */ - - ASM_OUTPUT_ALIGN (asm_out_file, align); + 5: Number of bytes in this header. + 6: address of table of function checksums (LPBX7). */ - ASM_OUTPUT_INTERNAL_LABEL (asm_out_file, "LPBX", 0); - - /* Zero word. */ - assemble_integer (const0_rtx, long_bytes, align2, 1); + /* The zero word. */ + decl_chain = + build_decl (FIELD_DECL, get_identifier ("zero_word"), + long_integer_type_node); + value_chain = build_tree_list (decl_chain, integer_zero_node); /* Address of filename. */ - ASM_GENERATE_INTERNAL_LABEL (name, "LPBX", 1); - assemble_integer (gen_rtx_SYMBOL_REF (Pmode, name), pointer_bytes, - align2, 1); + { + char *cwd = getpwd (); + int da_filename_len = strlen (filename) + strlen (cwd) + 4 + 1; + char *da_filename = (char *) alloca (da_filename_len); + + strcpy (da_filename, cwd); + strcat (da_filename, "/"); + strcat (da_filename, filename); + strip_off_ending (da_filename, da_filename_len - 3); + strcat (da_filename, ".da"); + field_decl = + build_decl (FIELD_DECL, get_identifier ("filename"), string_type); + string_cst = build_string (strlen (da_filename) + 1, da_filename); + domain_type = build_index_type (build_int_2 (strlen (da_filename) + 1, + 0)); + TREE_TYPE (string_cst) = + build_array_type (char_type_node, domain_type); + value_chain = tree_cons (field_decl, + build1 (ADDR_EXPR, string_type, string_cst), + value_chain); + TREE_CHAIN (field_decl) = decl_chain; + decl_chain = field_decl; + } - /* Address of count table. */ - ASM_GENERATE_INTERNAL_LABEL (name, "LPBX", 2); - assemble_integer (gen_rtx_SYMBOL_REF (Pmode, name), pointer_bytes, - align2, 1); + /* Table of counts. */ + { + tree gcov_type_type = make_unsigned_type (GCOV_TYPE_SIZE); + tree gcov_type_pointer_type = build_pointer_type (gcov_type_type); + tree gcov_type_array_type, gcov_type_array_pointer_type; + tree domain_tree = build_index_type (build_int_2 + (profile_info. + count_instrumented_edges - 1, + 0)); + tree counts_table; + + gcov_type_array_type = build_array_type (gcov_type_type, domain_tree); + gcov_type_array_pointer_type = + build_pointer_type (gcov_type_array_type); + + /* No values. */ + counts_table = + build (VAR_DECL, gcov_type_array_type, NULL_TREE, NULL_TREE); + TREE_STATIC (counts_table) = 1; + ASM_GENERATE_INTERNAL_LABEL (name, "LPBX", 2); + DECL_NAME (counts_table) = get_identifier (name); + assemble_variable (counts_table, 0, 0, 0); + + field_decl = + build_decl (FIELD_DECL, get_identifier ("counts"), + gcov_type_pointer_type); + value_chain = tree_cons (field_decl, + build1 (ADDR_EXPR, + gcov_type_array_pointer_type, + counts_table), value_chain); + TREE_CHAIN (field_decl) = decl_chain; + decl_chain = field_decl; + } /* Count of the # of instrumented arcs. */ - assemble_integer (GEN_INT (count_instrumented_edges), - long_bytes, align2, 1); + field_decl = + build_decl (FIELD_DECL, get_identifier ("ncounts"), + long_integer_type_node); + value_chain = tree_cons (field_decl, + convert (long_integer_type_node, + build_int_2 (profile_info. + count_instrumented_edges, + 0)), value_chain); + TREE_CHAIN (field_decl) = decl_chain; + decl_chain = field_decl; + + /* Pointer to the next bb. */ + field_decl = + build_decl (FIELD_DECL, get_identifier ("next"), + structure_pointer_type); + value_chain = tree_cons (field_decl, null_pointer_node, value_chain); + TREE_CHAIN (field_decl) = decl_chain; + decl_chain = field_decl; + + /* Number of words. We'll set this after entire structure is laid out. */ + field_decl = + build_decl (FIELD_DECL, get_identifier ("nwords"), + long_integer_type_node); + value_chain = nwords_field_value = + tree_cons (field_decl, NULL, value_chain); + TREE_CHAIN (field_decl) = decl_chain; + decl_chain = field_decl; + + /* struct bb_function []. */ + { + struct function_list *item; + int num_nodes; + tree checksum_field, arc_count_field, name_field; + tree domain; + tree array_value_chain = NULL_TREE; + tree bb_fn_struct_type; + tree bb_fn_struct_array_type; + tree bb_fn_struct_array_pointer_type; + tree bb_fn_struct_pointer_type; + tree field_value, field_value_chain; + + bb_fn_struct_type = make_node (RECORD_TYPE); + TYPE_PACKED (bb_fn_struct_type) = flag_pack_struct; + + checksum_field = build_decl (FIELD_DECL, get_identifier ("checksum"), + long_integer_type_node); + arc_count_field = + build_decl (FIELD_DECL, get_identifier ("arc_count"), + integer_type_node); + TREE_CHAIN (checksum_field) = arc_count_field; + name_field = + build_decl (FIELD_DECL, get_identifier ("name"), string_type); + TREE_CHAIN (arc_count_field) = name_field; + + TYPE_FIELDS (bb_fn_struct_type) = checksum_field; + + num_nodes = 0; + + for (item = functions_head; item != 0; item = item->next) + num_nodes++; + + /* Note that the array contains a terminator, hence no - 1. */ + domain = build_index_type (build_int_2 (num_nodes, 0)); + + bb_fn_struct_pointer_type = build_pointer_type (bb_fn_struct_type); + bb_fn_struct_array_type = build_array_type (bb_fn_struct_type, + domain); + bb_fn_struct_array_pointer_type = + build_pointer_type (bb_fn_struct_array_type); + + layout_type (bb_fn_struct_type); + layout_type (bb_fn_struct_pointer_type); + layout_type (bb_fn_struct_array_type); + layout_type (bb_fn_struct_array_pointer_type); + + for (item = functions_head; item != 0; item = item->next) + { + /* create constructor for structure. */ + field_value_chain = build_tree_list (checksum_field, + convert + (long_integer_type_node, + build_int_2 (item-> + cfg_checksum, + 0))); + field_value_chain = + tree_cons (arc_count_field, + convert (integer_type_node, + build_int_2 (item->count_edges, 0)), + field_value_chain); + + string_cst = build_string (strlen (item->name) + 1, item->name); + domain_type = build_index_type (build_int_2 (strlen (item->name) + + 1, 0)); + TREE_TYPE (string_cst) = build_array_type (char_type_node, + domain_type); + field_value_chain = tree_cons (name_field, + build1 (ADDR_EXPR, string_type, + string_cst), + field_value_chain); + + /* Add to chain. */ + + array_value_chain = tree_cons (NULL_TREE, + build (CONSTRUCTOR, + bb_fn_struct_type, + NULL_TREE, + nreverse + (field_value_chain)), + array_value_chain); + } - /* Zero word (link field). */ - assemble_integer (const0_rtx, pointer_bytes, align2, 1); + /* Add terminator. */ + field_value = build_tree_list (arc_count_field, + convert (integer_type_node, + build_int_2 (-1, 0))); + + array_value_chain = tree_cons (NULL_TREE, + build (CONSTRUCTOR, bb_fn_struct_type, + NULL_TREE, field_value), + array_value_chain); + + + /* Create constructor for array. */ + + field_decl = + build_decl (FIELD_DECL, get_identifier ("function_infos"), + bb_fn_struct_pointer_type); + value_chain = tree_cons (field_decl, + build1 (ADDR_EXPR, + bb_fn_struct_array_pointer_type, + build (CONSTRUCTOR, + bb_fn_struct_array_type, + NULL_TREE, + nreverse + (array_value_chain))), + value_chain); + TREE_CHAIN (field_decl) = decl_chain; + decl_chain = field_decl; + } - assemble_integer (const0_rtx, pointer_bytes, align2, 1); - /* Byte count for extended structure. */ - assemble_integer (GEN_INT (11 * UNITS_PER_WORD), long_bytes, align2, 1); + /* Finish structure. */ + TYPE_FIELDS (structure_decl) = nreverse (decl_chain); + layout_type (structure_decl); - /* Address of function name table. */ - assemble_integer (const0_rtx, pointer_bytes, align2, 1); + structure_value = + build (VAR_DECL, structure_decl, NULL_TREE, NULL_TREE); + DECL_INITIAL (structure_value) = + build (CONSTRUCTOR, structure_decl, NULL_TREE, + nreverse (value_chain)); + TREE_STATIC (structure_value) = 1; + ASM_GENERATE_INTERNAL_LABEL (name, "LPBX", 0); + DECL_NAME (structure_value) = get_identifier (name); - /* Address of line number and filename tables if debugging. */ - assemble_integer (const0_rtx, pointer_bytes, align2, 1); - assemble_integer (const0_rtx, pointer_bytes, align2, 1); + /* Set number of words in this structure. */ + TREE_VALUE (nwords_field_value) = + build_int_2 (TREE_INT_CST_LOW (TYPE_SIZE_UNIT (structure_decl)) / + (INT_TYPE_SIZE / BITS_PER_UNIT), 0); - /* Space for extension ptr (link field). */ - assemble_integer (const0_rtx, UNITS_PER_WORD, align2, 1); + /* Build structure. */ + assemble_variable (structure_value, 0, 0, 0); - /* Output the file name changing the suffix to .d for - Sun tcov compatibility. */ - ASM_OUTPUT_INTERNAL_LABEL (asm_out_file, "LPBX", 1); + /* Offset to table of arc counters for thread-safe profiling. */ { - char *cwd = getpwd (); - int len = strlen (filename) + strlen (cwd) + 1; - char *data_file = (char *) alloca (len + 4); - - strcpy (data_file, cwd); - strcat (data_file, "/"); - strcat (data_file, filename); - strip_off_ending (data_file, len); - strcat (data_file, ".da"); - assemble_string (data_file, strlen (data_file) + 1); + tree table_offset_var = make_node (VAR_DECL); + TREE_TYPE (table_offset_var) = build_pointer_type (integer_type_node); + DECL_INITIAL (table_offset_var) = integer_zero_node; + DECL_NAME (table_offset_var) = get_identifier (".LPBF0"); + TREE_STATIC (table_offset_var) = 1; + assemble_variable (table_offset_var, 0, 0, 0); } - - /* Make space for the table of counts. */ - if (size == 0) - { - /* Realign data section. */ - ASM_OUTPUT_ALIGN (asm_out_file, align); - ASM_OUTPUT_INTERNAL_LABEL (asm_out_file, "LPBX", 2); - if (size != 0) - assemble_zeros (size); - } - else - { - ASM_GENERATE_INTERNAL_LABEL (name, "LPBX", 2); -#ifdef ASM_OUTPUT_SHARED_LOCAL - if (flag_shared_data) - ASM_OUTPUT_SHARED_LOCAL (asm_out_file, name, size, rounded); - else -#endif -#ifdef ASM_OUTPUT_ALIGNED_DECL_LOCAL - ASM_OUTPUT_ALIGNED_DECL_LOCAL (asm_out_file, NULL_TREE, name, - size, BIGGEST_ALIGNMENT); -#else -#ifdef ASM_OUTPUT_ALIGNED_LOCAL - ASM_OUTPUT_ALIGNED_LOCAL (asm_out_file, name, size, - BIGGEST_ALIGNMENT); -#else - ASM_OUTPUT_LOCAL (asm_out_file, name, size, rounded); -#endif -#endif - } } } @@ -1781,6 +1930,24 @@ final (first, file, optimize, prescan) insn = final_scan_insn (insn, file, optimize, prescan, 0); } + /* Store function names for edge-profiling. */ + + if (profile_arc_flag) + { + struct function_list *new_item = xmalloc (sizeof (struct function_list)); + + /* Add function to linked list. */ + new_item->next = 0; + *functions_tail = new_item; + functions_tail = &new_item->next; + + /* Set values. */ + new_item->cfg_checksum = profile_info.current_function_cfg_checksum; + new_item->count_edges = profile_info.count_edges_instrumented_now; + new_item->name = xstrdup (current_function_name); + + } + free (line_note_exists); line_note_exists = NULL; } |