Index: gcc/tree-profile.c |
diff --git a/gcc/tree-profile.c b/gcc/tree-profile.c |
index 59d37666dbe1740a85e6a28340f3cfde923c0a60..887643b369f92e61f9ea282067120d8a896ed019 100644 |
--- a/gcc/tree-profile.c |
+++ b/gcc/tree-profile.c |
@@ -436,35 +436,85 @@ tree_gen_ior_profiler (histogram_value value, unsigned tag, unsigned base) |
static void |
tree_gen_thread_suspension_instrumentation (edge e) |
{ |
- static tree tree_suspend_thread_fn = NULL_TREE; |
+ static tree suspend_thread_fn = NULL_TREE; |
+ static tree thread_suspension_needed_var = NULL_TREE; |
+ |
+ tree tmp_var; |
+ |
+ basic_block bb_if; |
+ basic_block bb_call; |
+ basic_block bb_dest; |
- basic_block bb; |
gimple_stmt_iterator gsi; |
gimple stmt; |
- if (tree_suspend_thread_fn == NULL_TREE) |
+ if (suspend_thread_fn == NULL_TREE) |
{ |
- tree type = build_function_type (void_type_node, void_list_node); |
- tree id = get_identifier ("__nacl_suspend_thread_if_needed"); |
- tree decl = build_decl (FUNCTION_DECL, id, type); |
+ /* void __nacl_suspend_thread_if_needed (void); */ |
+ |
+ suspend_thread_fn = build_decl ( |
+ FUNCTION_DECL, |
+ get_identifier ("__nacl_suspend_thread_if_needed"), |
+ build_function_type (void_type_node, void_list_node)); |
+ |
+ TREE_PUBLIC (suspend_thread_fn) = 1; |
+ DECL_EXTERNAL (suspend_thread_fn) = 1; |
+ |
+ SET_DECL_ASSEMBLER_NAME ( |
+ suspend_thread_fn, |
+ get_identifier ("__nacl_suspend_thread_if_needed")); |
- tree libname = get_identifier ("__nacl_suspend_thread_if_needed"); |
+ /* volatile int __nacl_thread_suspension_needed; */ |
- TREE_PUBLIC (decl) = 1; |
- DECL_EXTERNAL (decl) = 1; |
+ thread_suspension_needed_var = build_decl ( |
+ VAR_DECL, |
+ get_identifier ("__nacl_thread_suspension_needed"), |
+ integer_type_node); |
- SET_DECL_ASSEMBLER_NAME (decl, libname); |
+ TREE_STATIC (thread_suspension_needed_var) = 1; |
+ TREE_PUBLIC (thread_suspension_needed_var) = 1; |
+ DECL_EXTERNAL (thread_suspension_needed_var) = 1; |
+ TREE_USED (thread_suspension_needed_var) = 1; |
+ TREE_THIS_VOLATILE (thread_suspension_needed_var) = 1; |
- tree_suspend_thread_fn = decl; |
+ SET_DECL_ASSEMBLER_NAME ( |
+ thread_suspension_needed_var, |
+ get_identifier ("__nacl_thread_suspension_needed")); |
} |
- bb = split_edge (e); |
- gsi = gsi_start_bb (bb); |
+ /* tmp = __nacl_thread_suspension_needed; |
+ if (tmp) |
+ { |
+ __nacl_suspend_thread_if_needed (); |
+ } |
- stmt = gimple_build_call (tree_suspend_thread_fn, 0); |
+ Temporary variable is needed to keep SSA happy. */ |
- gsi_insert_after (&gsi, stmt, GSI_NEW_STMT); |
- add_abnormal_goto_call_edges (gsi); |
+ bb_dest = e->dest; |
+ |
+ bb_if = split_edge (e); |
+ |
+ gsi = gsi_start_bb (bb_if); |
+ tmp_var = create_tmp_var (integer_type_node, NULL); |
+ stmt = gimple_build_assign (tmp_var, thread_suspension_needed_var); |
+ gsi_insert_before (&gsi, stmt, GSI_SAME_STMT); |
+ stmt = gimple_build_cond ( |
+ NE_EXPR, |
+ tmp_var, |
+ build_int_cst (integer_type_node, 0), |
+ NULL_TREE, |
+ NULL_TREE); |
+ gsi_insert_before (&gsi, stmt, GSI_SAME_STMT); |
+ |
+ bb_call = split_edge (single_succ_edge (bb_if)); |
+ |
+ gsi = gsi_start_bb (bb_call); |
+ stmt = gimple_build_call (suspend_thread_fn, 0); |
+ gsi_insert_before (&gsi, stmt, GSI_SAME_STMT); |
+ |
+ remove_edge (single_succ_edge (bb_if)); |
+ make_edge(bb_if, bb_dest, EDGE_FALSE_VALUE); |
+ make_edge(bb_if, bb_call, EDGE_TRUE_VALUE); |
} |
/* Return 1 if tree-based profiling is in effect, else 0. |
@@ -496,20 +546,51 @@ tree_profiling (void) |
basic_block bb; |
edge e; |
edge_iterator ei; |
+ edge *edges; |
+ int n; |
+ int i; |
+ /* Force back edges to be marked. */ |
mark_dfs_back_edges (); |
+ /* Instrument edges. |
+ Actual instrumentation adds basic blocks and adds/removes edges, thus |
+ making iterators unhappy. Build a list of edges to instrument before |
+ changing anything. */ |
+ |
+ /* Count back edges. */ |
+ n = 0; |
+ FOR_EACH_BB (bb) |
+ { |
+ FOR_EACH_EDGE (e, ei, bb->preds) |
+ { |
+ if (e->flags & EDGE_DFS_BACK) |
+ ++n; |
+ } |
+ } |
+ |
+ /* Add function entry edge at pos 0. */ |
+ ++n; |
+ edges = (edge *) alloca (n * sizeof (edge)); |
+ edges[0] = single_succ_edge (ENTRY_BLOCK_PTR); |
+ |
+ /* Populate back edges. */ |
+ i = 1; |
FOR_EACH_BB (bb) |
{ |
FOR_EACH_EDGE (e, ei, bb->preds) |
{ |
- /* Instrument beginning of the function and back edges. */ |
- if (e->src == ENTRY_BLOCK_PTR |
- || e->flags & EDGE_DFS_BACK) |
- tree_gen_thread_suspension_instrumentation (e); |
+ if (e->flags & EDGE_DFS_BACK) |
+ edges[i++] = e; |
} |
} |
+ /* Instrument edges. */ |
+ for (i = 0; i < n; ++i) |
+ { |
+ tree_gen_thread_suspension_instrumentation (edges[i]); |
+ } |
+ |
/* HACK: exit if we only need thread suspension instrumentation. */ |
if (!(profile_arc_flag || flag_test_coverage || flag_branch_probabilities)) |
return 0; |