aboutsummaryrefslogtreecommitdiff
path: root/gcc/tree-cfg.cc
diff options
context:
space:
mode:
Diffstat (limited to 'gcc/tree-cfg.cc')
-rw-r--r--gcc/tree-cfg.cc331
1 files changed, 118 insertions, 213 deletions
diff --git a/gcc/tree-cfg.cc b/gcc/tree-cfg.cc
index 6a95b82..3d23f17 100644
--- a/gcc/tree-cfg.cc
+++ b/gcc/tree-cfg.cc
@@ -114,43 +114,6 @@ struct replace_decls_d
tree to_context;
};
-/* Hash table to store last discriminator assigned for each locus. */
-struct locus_discrim_map
-{
- int location_line;
- int discriminator;
-};
-
-/* Hashtable helpers. */
-
-struct locus_discrim_hasher : free_ptr_hash <locus_discrim_map>
-{
- static inline hashval_t hash (const locus_discrim_map *);
- static inline bool equal (const locus_discrim_map *,
- const locus_discrim_map *);
-};
-
-/* Trivial hash function for a location_t. ITEM is a pointer to
- a hash table entry that maps a location_t to a discriminator. */
-
-inline hashval_t
-locus_discrim_hasher::hash (const locus_discrim_map *item)
-{
- return item->location_line;
-}
-
-/* Equality function for the locus-to-discriminator map. A and B
- point to the two hash table entries to compare. */
-
-inline bool
-locus_discrim_hasher::equal (const locus_discrim_map *a,
- const locus_discrim_map *b)
-{
- return a->location_line == b->location_line;
-}
-
-static hash_table<locus_discrim_hasher> *discriminator_per_locus;
-
/* Basic blocks and flowgraphs. */
static void make_blocks (gimple_seq);
@@ -168,7 +131,6 @@ static edge gimple_try_redirect_by_replacing_jump (edge, basic_block);
static inline bool stmt_starts_bb_p (gimple *, gimple *);
static bool gimple_verify_flow_info (void);
static void gimple_make_forwarder_block (edge);
-static gimple *first_non_label_nondebug_stmt (basic_block);
static bool verify_gimple_transaction (gtransaction *);
static bool call_can_make_abnormal_goto (gimple *);
@@ -247,12 +209,9 @@ build_gimple_cfg (gimple_seq seq)
group_case_labels ();
/* Create the edges of the flowgraph. */
- discriminator_per_locus = new hash_table<locus_discrim_hasher> (13);
make_edges ();
assign_discriminators ();
cleanup_dead_labels ();
- delete discriminator_per_locus;
- discriminator_per_locus = NULL;
}
/* Look for ANNOTATE calls with loop annotation kind in BB; if found, remove
@@ -1120,77 +1079,41 @@ gimple_find_sub_bbs (gimple_seq seq, gimple_stmt_iterator *gsi)
return true;
}
-/* 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 (int line)
-{
- struct locus_discrim_map item;
- struct locus_discrim_map **slot;
-
- item.location_line = line;
- item.discriminator = 0;
- slot = discriminator_per_locus->find_slot_with_hash (&item, line, INSERT);
- gcc_assert (slot);
- if (*slot == HTAB_EMPTY_ENTRY)
- {
- *slot = XNEW (struct locus_discrim_map);
- gcc_assert (*slot);
- (*slot)->location_line = line;
- (*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, expanded_location *from, location_t locus2)
+/* Auto-profile needs discriminator to distinguish statements with same line
+ number (file name is ignored) which are in different basic block. This
+ map keeps track of current discriminator for a given line number. */
+struct discrim_entry
{
- expanded_location to;
-
- if (locus1 == locus2)
- return true;
-
- 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
- && filename_cmp (from->file, to.file) == 0);
-}
+ /* ID of basic block we saw line number last time. */
+ unsigned int bb_id;
+ /* Discriminator we used. */
+ unsigned int discrim;
+};
-/* Assign a unique discriminator value to all statements in block bb that
- have the same line number as locus. */
+/* Return updated LOC with discriminator for use in basic block BB_ID.
+ MAP keeps track of current values. */
-static void
-assign_discriminator (location_t locus, basic_block bb)
+location_t
+assign_discriminator (location_t loc, unsigned int bb_id,
+ hash_map<int_hash <int64_t, -1, -2>, discrim_entry> &map)
{
- gimple_stmt_iterator gsi;
- int discriminator;
-
- if (locus == UNKNOWN_LOCATION)
- return;
-
- expanded_location locus_e = expand_location (locus);
-
- discriminator = next_discriminator_for_locus (locus_e.line);
-
- for (gsi = gsi_start_bb (bb); !gsi_end_p (gsi); gsi_next (&gsi))
+ bool existed;
+ discrim_entry &e = map.get_or_insert (LOCATION_LINE (loc), &existed);
+ gcc_checking_assert (!has_discriminator (loc));
+ if (!existed)
{
- gimple *stmt = gsi_stmt (gsi);
- location_t stmt_locus = gimple_location (stmt);
- if (same_line_p (locus, &locus_e, stmt_locus))
- gimple_set_location (stmt,
- location_with_discriminator (stmt_locus, discriminator));
+ e.bb_id = bb_id;
+ e.discrim = 0;
+ return loc;
}
+ if (e.bb_id != bb_id)
+ {
+ e.bb_id = bb_id;
+ e.discrim++;
+ }
+ if (e.discrim)
+ return location_with_discriminator (loc, e.discrim);
+ return loc;
}
/* Assign discriminators to statement locations. */
@@ -1198,92 +1121,54 @@ assign_discriminator (location_t locus, basic_block bb)
static void
assign_discriminators (void)
{
+ hash_map<int_hash <int64_t, -1, -2>, discrim_entry> map (13);
+ unsigned int bb_id = 0;
basic_block bb;
-
FOR_EACH_BB_FN (bb, cfun)
{
- edge e;
- edge_iterator ei;
- gimple_stmt_iterator gsi;
- location_t curr_locus = UNKNOWN_LOCATION;
- expanded_location curr_locus_e = {};
- int curr_discr = 0;
-
+ location_t prev_loc = UNKNOWN_LOCATION, prev_replacement = UNKNOWN_LOCATION;
/* Traverse the basic block, if two function calls within a basic block
are mapped to the same line, assign a new discriminator because a call
stmt could be a split point of a basic block. */
- for (gsi = gsi_start_bb (bb); !gsi_end_p (gsi); gsi_next (&gsi))
+ for (gimple_stmt_iterator gsi = gsi_start_bb (bb);
+ !gsi_end_p (gsi); gsi_next (&gsi))
{
gimple *stmt = gsi_stmt (gsi);
-
- /* Don't allow debug stmts to affect discriminators, but
- allow them to take discriminators when they're on the
- same line as the preceding nondebug stmt. */
- if (is_gimple_debug (stmt))
- {
- if (curr_locus != UNKNOWN_LOCATION
- && same_line_p (curr_locus, &curr_locus_e,
- gimple_location (stmt)))
- {
- location_t loc = gimple_location (stmt);
- location_t dloc = location_with_discriminator (loc,
- curr_discr);
- gimple_set_location (stmt, dloc);
- }
- continue;
- }
- if (curr_locus == UNKNOWN_LOCATION)
- {
- curr_locus = gimple_location (stmt);
- curr_locus_e = expand_location (curr_locus);
- }
- else if (!same_line_p (curr_locus, &curr_locus_e, gimple_location (stmt)))
- {
- curr_locus = gimple_location (stmt);
- curr_locus_e = expand_location (curr_locus);
- curr_discr = 0;
- }
- else if (curr_discr != 0)
+ location_t loc = gimple_location (stmt);
+ if (loc == UNKNOWN_LOCATION)
+ continue;
+ if (loc == prev_loc)
+ gimple_set_location (stmt, prev_replacement);
+ else
{
- location_t loc = gimple_location (stmt);
- location_t dloc = location_with_discriminator (loc, curr_discr);
- gimple_set_location (stmt, dloc);
+ prev_loc = loc;
+ prev_replacement = assign_discriminator (loc, bb_id, map);
+ gimple_set_location (stmt, prev_replacement);
}
- /* Allocate a new discriminator for CALL stmt. */
+ /* Break basic blocks after each call. This is requires so each
+ call site has unque discriminator.
+ More correctly, we can break after each statement that can possibly
+ terinate execution of the basic block, but for auto-profile this
+ precision is probably not useful. */
if (gimple_code (stmt) == GIMPLE_CALL)
- curr_discr = next_discriminator_for_locus (curr_locus_e.line);
- }
-
- gimple *last = last_nondebug_stmt (bb);
- location_t locus = last ? gimple_location (last) : UNKNOWN_LOCATION;
- if (locus == UNKNOWN_LOCATION)
- continue;
-
- expanded_location locus_e = expand_location (locus);
-
- FOR_EACH_EDGE (e, ei, bb->succs)
- {
- gimple *first = first_non_label_nondebug_stmt (e->dest);
- gimple *last = last_nondebug_stmt (e->dest);
-
- gimple *stmt_on_same_line = NULL;
- if (first && same_line_p (locus, &locus_e,
- gimple_location (first)))
- stmt_on_same_line = first;
- else if (last && same_line_p (locus, &locus_e,
- gimple_location (last)))
- stmt_on_same_line = last;
-
- if (stmt_on_same_line)
{
- if (has_discriminator (gimple_location (stmt_on_same_line))
- && !has_discriminator (locus))
- assign_discriminator (locus, bb);
- else
- assign_discriminator (locus, e->dest);
+ prev_loc = UNKNOWN_LOCATION;
+ bb_id++;
}
}
+ /* IF basic block has multiple sucessors, consdier every edge as a separate
+ block. */
+ if (!single_succ_p (bb))
+ bb_id++;
+ for (edge e : bb->succs)
+ if (e->goto_locus != UNKNOWN_LOCATION)
+ {
+ e->goto_locus = assign_discriminator (e->goto_locus, bb_id, map);
+ bb_id++;
+ }
+ bb_id++;
}
+
}
/* Create the edges for a GIMPLE_COND starting at block BB. */
@@ -2948,16 +2833,6 @@ first_stmt (basic_block bb)
return stmt;
}
-/* Return the first non-label/non-debug statement in basic block BB. */
-
-static gimple *
-first_non_label_nondebug_stmt (basic_block bb)
-{
- gimple_stmt_iterator i;
- i = gsi_start_nondebug_after_labels_bb (bb);
- return !gsi_end_p (i) ? gsi_stmt (i) : NULL;
-}
-
/* Return the last statement in basic block BB. */
gimple *
@@ -3867,22 +3742,6 @@ verify_gimple_assign_unary (gassign *stmt)
return false;
- case NEGATE_EXPR:
- case ABS_EXPR:
- case BIT_NOT_EXPR:
- case PAREN_EXPR:
- case CONJ_EXPR:
- /* Disallow pointer and offset types for many of the unary gimple. */
- if (POINTER_TYPE_P (lhs_type)
- || TREE_CODE (lhs_type) == OFFSET_TYPE)
- {
- error ("invalid types for %qs", code_name);
- debug_generic_expr (lhs_type);
- debug_generic_expr (rhs1_type);
- return true;
- }
- break;
-
case ABSU_EXPR:
if (!ANY_INTEGRAL_TYPE_P (lhs_type)
|| !TYPE_UNSIGNED (lhs_type)
@@ -3908,6 +3767,27 @@ verify_gimple_assign_unary (gassign *stmt)
}
return false;
+ case CONJ_EXPR:
+ if (TREE_CODE (lhs_type) != COMPLEX_TYPE)
+ {
+diagnose_unary_lhs:
+ error ("invalid type for %qs", code_name);
+ debug_generic_expr (lhs_type);
+ return true;
+ }
+ break;
+
+ case NEGATE_EXPR:
+ case ABS_EXPR:
+ case BIT_NOT_EXPR:
+ if (POINTER_TYPE_P (lhs_type) || TREE_CODE (lhs_type) == OFFSET_TYPE)
+ goto diagnose_unary_lhs;
+ /* FALLTHRU */
+ case PAREN_EXPR:
+ if (AGGREGATE_TYPE_P (lhs_type))
+ goto diagnose_unary_lhs;
+ break;
+
default:
gcc_unreachable ();
}
@@ -4618,6 +4498,14 @@ verify_gimple_assign_single (gassign *stmt)
return true;
}
+ /* LHS can't be a constant or an address expression. */
+ if (CONSTANT_CLASS_P (lhs)|| TREE_CODE (lhs) == ADDR_EXPR)
+ {
+ error ("invalid LHS (%qs) for assignment: %qs",
+ get_tree_code_name (TREE_CODE (lhs)), code_name);
+ return true;
+ }
+
if (gimple_clobber_p (stmt)
&& !(DECL_P (lhs) || TREE_CODE (lhs) == MEM_REF))
{
@@ -4740,6 +4628,11 @@ verify_gimple_assign_single (gassign *stmt)
if (CONSTRUCTOR_NELTS (rhs1) == 0)
return res;
+ if (!is_gimple_reg (lhs))
+ {
+ error ("non-register as LHS with vector constructor");
+ return true;
+ }
/* For vector CONSTRUCTORs we require that either it is empty
CONSTRUCTOR, or it is a CONSTRUCTOR of smaller vector elements
(then the element count must be correct to cover the whole
@@ -5752,6 +5645,12 @@ gimple_verify_flow_info (void)
error ("probability of edge from entry block not initialized");
err = true;
}
+ if (!EXIT_BLOCK_PTR_FOR_FN (cfun)
+ ->count.compatible_p (ENTRY_BLOCK_PTR_FOR_FN (cfun)->count))
+ {
+ error ("exit block count is not compatible with entry block count");
+ err = true;
+ }
FOR_EACH_BB_FN (bb, cfun)
@@ -5775,6 +5674,12 @@ gimple_verify_flow_info (void)
err = true;
}
}
+ if (!bb->count.compatible_p (ENTRY_BLOCK_PTR_FOR_FN (cfun)->count))
+ {
+ error ("count of bb %d is not compatible with entry block count",
+ bb->index);
+ err = true;
+ }
/* Skip labels on the start of basic block. */
for (gsi = gsi_start_bb (bb); !gsi_end_p (gsi); gsi_next (&gsi))
@@ -8322,7 +8227,7 @@ dump_function_to_file (tree fndecl, FILE *file, dump_flags_t flags)
fprintf (file, ", ");
tree name = get_attribute_name (chain);
- print_generic_expr (file, name, dump_flags);
+ print_generic_expr (file, name, flags);
if (TREE_VALUE (chain) != NULL_TREE)
{
fprintf (file, " (");
@@ -8333,13 +8238,13 @@ dump_function_to_file (tree fndecl, FILE *file, dump_flags_t flags)
"omp declare variant base"))
{
tree a = TREE_VALUE (chain);
- print_generic_expr (file, TREE_PURPOSE (a), dump_flags);
+ print_generic_expr (file, TREE_PURPOSE (a), flags);
fprintf (file, " match ");
print_omp_context_selector (file, TREE_VALUE (a),
- dump_flags);
+ flags);
}
else
- print_generic_expr (file, TREE_VALUE (chain), dump_flags);
+ print_generic_expr (file, TREE_VALUE (chain), flags);
fprintf (file, ")");
}
}
@@ -8361,7 +8266,7 @@ dump_function_to_file (tree fndecl, FILE *file, dump_flags_t flags)
}
print_generic_expr (file, TREE_TYPE (TREE_TYPE (fndecl)),
- dump_flags | TDF_SLIM);
+ flags | TDF_SLIM);
fprintf (file, " __GIMPLE (%s",
(fun->curr_properties & PROP_ssa) ? "ssa"
: (fun->curr_properties & PROP_cfg) ? "cfg"
@@ -8374,7 +8279,7 @@ dump_function_to_file (tree fndecl, FILE *file, dump_flags_t flags)
fprintf (file, ",%s(%" PRIu64 ")",
profile_quality_as_string (bb->count.quality ()),
bb->count.value ());
- if (dump_flags & TDF_UID)
+ if (flags & TDF_UID)
fprintf (file, ")\n%sD_%u (", function_name (fun),
DECL_UID (fndecl));
else
@@ -8383,8 +8288,8 @@ dump_function_to_file (tree fndecl, FILE *file, dump_flags_t flags)
}
else
{
- print_generic_expr (file, TREE_TYPE (fntype), dump_flags);
- if (dump_flags & TDF_UID)
+ print_generic_expr (file, TREE_TYPE (fntype), flags);
+ if (flags & TDF_UID)
fprintf (file, " %sD.%u %s(", function_name (fun), DECL_UID (fndecl),
tmclone ? "[tm-clone] " : "");
else
@@ -8395,9 +8300,9 @@ dump_function_to_file (tree fndecl, FILE *file, dump_flags_t flags)
arg = DECL_ARGUMENTS (fndecl);
while (arg)
{
- print_generic_expr (file, TREE_TYPE (arg), dump_flags);
+ print_generic_expr (file, TREE_TYPE (arg), flags);
fprintf (file, " ");
- print_generic_expr (file, arg, dump_flags);
+ print_generic_expr (file, arg, flags);
if (DECL_CHAIN (arg))
fprintf (file, ", ");
arg = DECL_CHAIN (arg);