aboutsummaryrefslogtreecommitdiff
path: root/gcc/tree-cfg.c
diff options
context:
space:
mode:
authorCary Coutant <ccoutant@google.com>2009-06-04 23:12:27 +0000
committerCary Coutant <ccoutant@gcc.gnu.org>2009-06-04 16:12:27 -0700
commit6c52e687e487eb5bfc57399754d72e05845159d8 (patch)
tree62b2a3883be83cd19685457df195f788da6d5d99 /gcc/tree-cfg.c
parent535ff342b76110501c8673df1ae44db5e6ea55b4 (diff)
downloadgcc-6c52e687e487eb5bfc57399754d72e05845159d8.zip
gcc-6c52e687e487eb5bfc57399754d72e05845159d8.tar.gz
gcc-6c52e687e487eb5bfc57399754d72e05845159d8.tar.bz2
basic-block.h (struct basic_block_def): Add discriminator field.
* basic-block.h (struct basic_block_def): Add discriminator field. * dbxout.c (dbxout_source_line): Add new parameter. Change all callers. * debug.c (do_nothing_debug_hooks): Add additional entry. (debug_nothing_int_charstar_int): New function. * debug.h (struct gcc_debug_hooks): Add parameter to source_line hook. (debug_nothing_int_charstar_int): New declaration. * dwarf2out.c (dwarf2out_source_line): Add new parameter. Write discriminator value in .loc directive. * final.c (last_discriminator): New variable. (discriminator): New variable. (final_start_function): Initialize above variables, pass current discriminator to debug hook. (notice_source_line): Check for discriminator change. * gimple-pretty-print.c (dump_bb_header): Print discriminator value. * sdbout.c (sdbout_source_line): New parameter. * tree-cfg.c (struct locus_discrim_map): New structure type. (discriminator_per_locus): New hash table. (build_gimple_cfg): Allocate and free discriminator hash table. (make_edges): Call assign_discriminator. (locus_map_hash): New function. (locus_map_eq): New function. (next_discriminator_for_locus): New function. (same_line_p): New function. (assign_discriminator): New function. (make_cond_expr_edges): Call assign_discriminator. (make_gimple_switch_edges): Likewise. (first_non_label_stmt): New function. * vmsdbgout.c (vmsdbgout_source_line): Add new parameter. Change all callers. * xcoffout.c (xcoffout_source_line): Add new parameter. * configure.ac (gcc_cv_as_discriminator): New configury check for gas support for discriminator. * configure: Regenerate. * config.in: Regenerate. From-SVN: r148191
Diffstat (limited to 'gcc/tree-cfg.c')
-rw-r--r--gcc/tree-cfg.c130
1 files changed, 128 insertions, 2 deletions
diff --git a/gcc/tree-cfg.c b/gcc/tree-cfg.c
index 875dd8e..26a082d 100644
--- a/gcc/tree-cfg.c
+++ b/gcc/tree-cfg.c
@@ -82,6 +82,14 @@ static struct cfg_stats_d cfg_stats;
/* Nonzero if we found a computed goto while building basic blocks. */
static bool found_computed_goto;
+/* Hash table to store last discriminator assigned for each locus. */
+struct locus_discrim_map
+{
+ location_t locus;
+ int discriminator;
+};
+static htab_t discriminator_per_locus;
+
/* Basic blocks and flowgraphs. */
static void make_blocks (gimple_seq);
static void factor_computed_gotos (void);
@@ -91,6 +99,9 @@ static void make_edges (void);
static void make_cond_expr_edges (basic_block);
static void make_gimple_switch_edges (basic_block);
static void make_goto_expr_edges (basic_block);
+static unsigned int locus_map_hash (const void *);
+static int locus_map_eq (const void *, const void *);
+static void assign_discriminator (location_t, basic_block);
static edge gimple_redirect_edge_and_branch (edge, basic_block);
static edge gimple_try_redirect_by_replacing_jump (edge, basic_block);
static unsigned int split_critical_edges (void);
@@ -100,6 +111,7 @@ static inline bool stmt_starts_bb_p (gimple, gimple);
static int gimple_verify_flow_info (void);
static void gimple_make_forwarder_block (edge);
static void gimple_cfg2vcg (FILE *);
+static gimple first_non_label_stmt (basic_block);
/* Flowgraph optimization and cleanup. */
static void gimple_merge_blocks (basic_block, basic_block);
@@ -193,8 +205,11 @@ build_gimple_cfg (gimple_seq seq)
group_case_labels ();
/* Create the edges of the flowgraph. */
+ discriminator_per_locus = htab_create (13, locus_map_hash, locus_map_eq,
+ free);
make_edges ();
cleanup_dead_labels ();
+ htab_delete (discriminator_per_locus);
/* Debugging dumps. */
@@ -650,7 +665,11 @@ make_edges (void)
fallthru = true;
if (fallthru)
- make_edge (bb, bb->next_bb, EDGE_FALLTHRU);
+ {
+ make_edge (bb, bb->next_bb, EDGE_FALLTHRU);
+ if (last)
+ assign_discriminator (gimple_location (last), bb->next_bb);
+ }
}
if (root_omp_region)
@@ -660,6 +679,91 @@ make_edges (void)
fold_cond_expr_cond ();
}
+/* Trivial hash function for a location_t. ITEM is a pointer to
+ a hash table entry that maps a location_t to a discriminator. */
+
+static unsigned int
+locus_map_hash (const void *item)
+{
+ return ((const struct locus_discrim_map *) item)->locus;
+}
+
+/* Equality function for the locus-to-discriminator map. VA and VB
+ point to the two hash table entries to compare. */
+
+static int
+locus_map_eq (const void *va, const void *vb)
+{
+ const struct locus_discrim_map *a = (const struct locus_discrim_map *) va;
+ const struct locus_discrim_map *b = (const struct locus_discrim_map *) vb;
+ return a->locus == b->locus;
+}
+
+/* Find the next available discriminator value for LOCUS. The
+ discriminator distinguishes among several basic blocks that
+ share a common locus, allowing for more accurate sample-based
+ profiling. */
+
+static int
+next_discriminator_for_locus (location_t locus)
+{
+ struct locus_discrim_map item;
+ struct locus_discrim_map **slot;
+
+ item.locus = locus;
+ item.discriminator = 0;
+ slot = (struct locus_discrim_map **)
+ htab_find_slot_with_hash (discriminator_per_locus, (void *) &item,
+ (hashval_t) locus, INSERT);
+ gcc_assert (slot);
+ if (*slot == HTAB_EMPTY_ENTRY)
+ {
+ *slot = XNEW (struct locus_discrim_map);
+ gcc_assert (*slot);
+ (*slot)->locus = locus;
+ (*slot)->discriminator = 0;
+ }
+ (*slot)->discriminator++;
+ return (*slot)->discriminator;
+}
+
+/* Return TRUE if LOCUS1 and LOCUS2 refer to the same source line. */
+
+static bool
+same_line_p (location_t locus1, location_t locus2)
+{
+ expanded_location from, to;
+
+ if (locus1 == locus2)
+ return true;
+
+ from = expand_location (locus1);
+ to = expand_location (locus2);
+
+ if (from.line != to.line)
+ return false;
+ if (from.file == to.file)
+ return true;
+ return (from.file != NULL
+ && to.file != NULL
+ && strcmp (from.file, to.file) == 0);
+}
+
+/* Assign a unique discriminator value to block BB if it begins at the same
+ LOCUS as its predecessor block. */
+
+static void
+assign_discriminator (location_t locus, basic_block bb)
+{
+ gimple to_stmt;
+
+ if (locus == 0 || bb->discriminator != 0)
+ return;
+
+ to_stmt = first_non_label_stmt (bb);
+ if (to_stmt && same_line_p (locus, gimple_location (to_stmt)))
+ bb->discriminator = next_discriminator_for_locus (locus);
+}
/* Create the edges for a GIMPLE_COND starting at block BB. */
@@ -671,10 +775,13 @@ make_cond_expr_edges (basic_block bb)
basic_block then_bb, else_bb;
tree then_label, else_label;
edge e;
+ location_t entry_locus;
gcc_assert (entry);
gcc_assert (gimple_code (entry) == GIMPLE_COND);
+ entry_locus = gimple_location (entry);
+
/* Entry basic blocks for each component. */
then_label = gimple_cond_true_label (entry);
else_label = gimple_cond_false_label (entry);
@@ -684,12 +791,14 @@ make_cond_expr_edges (basic_block bb)
else_stmt = first_stmt (else_bb);
e = make_edge (bb, then_bb, EDGE_TRUE_VALUE);
+ assign_discriminator (entry_locus, then_bb);
e->goto_locus = gimple_location (then_stmt);
if (e->goto_locus)
e->goto_block = gimple_block (then_stmt);
e = make_edge (bb, else_bb, EDGE_FALSE_VALUE);
if (e)
{
+ assign_discriminator (entry_locus, else_bb);
e->goto_locus = gimple_location (else_stmt);
if (e->goto_locus)
e->goto_block = gimple_block (else_stmt);
@@ -799,8 +908,11 @@ static void
make_gimple_switch_edges (basic_block bb)
{
gimple entry = last_stmt (bb);
+ location_t entry_locus;
size_t i, n;
+ entry_locus = gimple_location (entry);
+
n = gimple_switch_num_labels (entry);
for (i = 0; i < n; ++i)
@@ -808,6 +920,7 @@ make_gimple_switch_edges (basic_block bb)
tree lab = CASE_LABEL (gimple_switch_label (entry, i));
basic_block label_bb = label_to_block (lab);
make_edge (bb, label_bb, 0);
+ assign_discriminator (entry_locus, label_bb);
}
}
@@ -880,8 +993,10 @@ make_goto_expr_edges (basic_block bb)
if (simple_goto_p (goto_t))
{
tree dest = gimple_goto_dest (goto_t);
- edge e = make_edge (bb, label_to_block (dest), EDGE_FALLTHRU);
+ basic_block label_bb = label_to_block (dest);
+ edge e = make_edge (bb, label_bb, EDGE_FALLTHRU);
e->goto_locus = gimple_location (goto_t);
+ assign_discriminator (e->goto_locus, label_bb);
if (e->goto_locus)
e->goto_block = gimple_block (goto_t);
gsi_remove (&last, true);
@@ -2690,6 +2805,17 @@ first_stmt (basic_block bb)
return !gsi_end_p (i) ? gsi_stmt (i) : NULL;
}
+/* Return the first non-label statement in basic block BB. */
+
+static gimple
+first_non_label_stmt (basic_block bb)
+{
+ gimple_stmt_iterator i = gsi_start_bb (bb);
+ while (!gsi_end_p (i) && gimple_code (gsi_stmt (i)) == GIMPLE_LABEL)
+ gsi_next (&i);
+ return !gsi_end_p (i) ? gsi_stmt (i) : NULL;
+}
+
/* Return the last statement in basic block BB. */
gimple