summaryrefslogtreecommitdiff
path: root/gcc/final.c
diff options
context:
space:
mode:
authorhubicka <hubicka@138bc75d-0d04-0410-961f-82ee72b054a4>2002-05-09 12:54:19 +0000
committerhubicka <hubicka@138bc75d-0d04-0410-961f-82ee72b054a4>2002-05-09 12:54:19 +0000
commit90c2be4439c656f63074408d6c91442511a9e061 (patch)
treeda04474c0297ae3c91b3bdce0c519ca2f9d2e5a8 /gcc/final.c
parent40734805198ef874623eb7be9ec3de9251c799b7 (diff)
downloadgcc-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.c383
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;
}