diff options
Diffstat (limited to 'gcc/tree-profile.c')
-rw-r--r-- | gcc/tree-profile.c | 106 |
1 files changed, 81 insertions, 25 deletions
diff --git a/gcc/tree-profile.c b/gcc/tree-profile.c index abeee92..09a702f 100644 --- a/gcc/tree-profile.c +++ b/gcc/tree-profile.c @@ -56,9 +56,9 @@ static GTY(()) tree tree_interval_profiler_fn; static GTY(()) tree tree_pow2_profiler_fn; static GTY(()) tree tree_one_value_profiler_fn; static GTY(()) tree tree_indirect_call_profiler_fn; -static GTY(()) tree tree_time_profiler_fn; static GTY(()) tree tree_average_profiler_fn; static GTY(()) tree tree_ior_profiler_fn; +static GTY(()) tree tree_time_profiler_counter; static GTY(()) tree ic_void_ptr_var; @@ -75,7 +75,7 @@ static GTY(()) tree ptr_void; static void init_ic_make_global_vars (void) { - tree gcov_type_ptr; + tree gcov_type_ptr; ptr_void = build_pointer_type (void_type_node); @@ -119,7 +119,7 @@ init_ic_make_global_vars (void) /* Create the type and function decls for the interface with gcov. */ void -gimple_init_edge_profiler (void) +gimple_init_gcov_profiler (void) { tree interval_profiler_fn_type; tree pow2_profiler_fn_type; @@ -127,7 +127,6 @@ gimple_init_edge_profiler (void) tree gcov_type_ptr; tree ic_profiler_fn_type; tree average_profiler_fn_type; - tree time_profiler_fn_type; const char *profiler_fn_name; const char *fn_name; @@ -201,17 +200,17 @@ gimple_init_edge_profiler (void) = tree_cons (get_identifier ("leaf"), NULL, DECL_ATTRIBUTES (tree_indirect_call_profiler_fn)); - /* void (*) (gcov_type *, gcov_type, void *) */ - time_profiler_fn_type - = build_function_type_list (void_type_node, - gcov_type_ptr, NULL_TREE); - fn_name = concat ("__gcov_time_profiler", fn_suffix, NULL); - tree_time_profiler_fn = build_fn_decl (fn_name, time_profiler_fn_type); - free (CONST_CAST (char *, fn_name)); - TREE_NOTHROW (tree_time_profiler_fn) = 1; - DECL_ATTRIBUTES (tree_time_profiler_fn) - = tree_cons (get_identifier ("leaf"), NULL, - DECL_ATTRIBUTES (tree_time_profiler_fn)); + tree_time_profiler_counter + = build_decl (UNKNOWN_LOCATION, VAR_DECL, + get_identifier ("__gcov_time_profiler_counter"), + get_gcov_type ()); + TREE_PUBLIC (tree_time_profiler_counter) = 1; + DECL_EXTERNAL (tree_time_profiler_counter) = 1; + TREE_STATIC (tree_time_profiler_counter) = 1; + DECL_ARTIFICIAL (tree_time_profiler_counter) = 1; + DECL_INITIAL (tree_time_profiler_counter) = NULL; + + varpool_node::finalize_decl (tree_time_profiler_counter); /* void (*) (gcov_type *, gcov_type) */ average_profiler_fn_type @@ -239,7 +238,6 @@ gimple_init_edge_profiler (void) DECL_ASSEMBLER_NAME (tree_pow2_profiler_fn); DECL_ASSEMBLER_NAME (tree_one_value_profiler_fn); DECL_ASSEMBLER_NAME (tree_indirect_call_profiler_fn); - DECL_ASSEMBLER_NAME (tree_time_profiler_fn); DECL_ASSEMBLER_NAME (tree_average_profiler_fn); DECL_ASSEMBLER_NAME (tree_ior_profiler_fn); } @@ -426,7 +424,7 @@ gimple_gen_ic_func_profiler (void) if (c_node->only_called_directly_p ()) return; - gimple_init_edge_profiler (); + gimple_init_gcov_profiler (); /* Insert code: @@ -460,16 +458,74 @@ gimple_gen_ic_func_profiler (void) counter position and GSI is the iterator we place the counter. */ void -gimple_gen_time_profiler (unsigned tag, unsigned base, - gimple_stmt_iterator &gsi) +gimple_gen_time_profiler (unsigned tag, unsigned base) { - tree ref_ptr = tree_coverage_counter_addr (tag, base); - gcall *call; + tree type = get_gcov_type (); + basic_block cond_bb + = split_edge (single_succ_edge (ENTRY_BLOCK_PTR_FOR_FN (cfun))); + + basic_block update_bb = split_edge (single_succ_edge (cond_bb)); + + edge true_edge = single_succ_edge (cond_bb); + true_edge->flags = EDGE_TRUE_VALUE; + true_edge->probability = PROB_VERY_UNLIKELY; + edge e + = make_edge (cond_bb, single_succ_edge (update_bb)->dest, EDGE_FALSE_VALUE); + e->probability = REG_BR_PROB_BASE - true_edge->probability; + + gimple_stmt_iterator gsi = gsi_start_bb (cond_bb); + tree original_ref = tree_coverage_counter_ref (tag, base); + tree ref = force_gimple_operand_gsi (&gsi, original_ref, true, NULL_TREE, + true, GSI_SAME_STMT); + tree one = build_int_cst (type, 1); - ref_ptr = force_gimple_operand_gsi (&gsi, ref_ptr, - true, NULL_TREE, true, GSI_SAME_STMT); - call = gimple_build_call (tree_time_profiler_fn, 1, ref_ptr); - gsi_insert_before (&gsi, call, GSI_NEW_STMT); + /* Emit: if (counters[0] != 0). */ + gcond *cond = gimple_build_cond (EQ_EXPR, ref, build_int_cst (type, 0), + NULL, NULL); + gsi_insert_before (&gsi, cond, GSI_NEW_STMT); + + gsi = gsi_start_bb (update_bb); + + /* Emit: counters[0] = ++__gcov_time_profiler_counter. */ + if (flag_profile_update == PROFILE_UPDATE_ATOMIC) + { + tree ptr = make_temp_ssa_name (type, NULL, "time_profiler_counter_ptr"); + tree addr = build1 (ADDR_EXPR, build_pointer_type (type), + tree_time_profiler_counter); + gassign *assign = gimple_build_assign (ptr, NOP_EXPR, addr); + gsi_insert_before (&gsi, assign, GSI_NEW_STMT); + tree f = builtin_decl_explicit (LONG_LONG_TYPE_SIZE > 32 + ? BUILT_IN_ATOMIC_ADD_FETCH_8: + BUILT_IN_ATOMIC_ADD_FETCH_4); + gcall *stmt = gimple_build_call (f, 3, ptr, one, + build_int_cst (integer_type_node, + MEMMODEL_RELAXED)); + tree result_type = TREE_TYPE (TREE_TYPE (f)); + tree tmp = make_temp_ssa_name (result_type, NULL, "time_profile"); + gimple_set_lhs (stmt, tmp); + gsi_insert_after (&gsi, stmt, GSI_NEW_STMT); + tmp = make_temp_ssa_name (type, NULL, "time_profile"); + assign = gimple_build_assign (tmp, NOP_EXPR, + gimple_call_lhs (stmt)); + gsi_insert_after (&gsi, assign, GSI_NEW_STMT); + assign = gimple_build_assign (original_ref, tmp); + gsi_insert_after (&gsi, assign, GSI_NEW_STMT); + } + else + { + tree tmp = make_temp_ssa_name (type, NULL, "time_profile"); + gassign *assign = gimple_build_assign (tmp, tree_time_profiler_counter); + gsi_insert_before (&gsi, assign, GSI_NEW_STMT); + + tmp = make_temp_ssa_name (type, NULL, "time_profile"); + assign = gimple_build_assign (tmp, PLUS_EXPR, gimple_assign_lhs (assign), + one); + gsi_insert_after (&gsi, assign, GSI_NEW_STMT); + assign = gimple_build_assign (original_ref, tmp); + gsi_insert_after (&gsi, assign, GSI_NEW_STMT); + assign = gimple_build_assign (tree_time_profiler_counter, tmp); + gsi_insert_after (&gsi, assign, GSI_NEW_STMT); + } } /* Output instructions as GIMPLE trees to increment the average histogram |