#include "config.h"
#include "system.h"
#include "coretypes.h"
#include "tm.h"
#include "rtl.h"
#include "flags.h"
#include "output.h"
#include "regs.h"
#include "expr.h"
#include "function.h"
#include "toplev.h"
#include "coverage.h"
#include "tree.h"
#include "tree-flow.h"
#include "tree-dump.h"
#include "tree-pass.h"
#include "timevar.h"
#include "value-prof.h"
#include "ggc.h"
static GTY(()) tree gcov_type_node;
static GTY(()) tree tree_interval_profiler_fn;
static GTY(()) tree tree_pow2_profiler_fn;
static GTY(()) tree tree_one_value_profiler_fn;
static void
tree_init_edge_profiler (void)
{
tree interval_profiler_fn_type;
tree pow2_profiler_fn_type;
tree one_value_profiler_fn_type;
tree gcov_type_ptr;
if (!gcov_type_node)
{
gcov_type_node = get_gcov_type ();
gcov_type_ptr = build_pointer_type (gcov_type_node);
interval_profiler_fn_type
= build_function_type_list (void_type_node,
gcov_type_ptr, gcov_type_node,
integer_type_node,
unsigned_type_node, NULL_TREE);
tree_interval_profiler_fn
= build_fn_decl ("__gcov_interval_profiler",
interval_profiler_fn_type);
pow2_profiler_fn_type
= build_function_type_list (void_type_node,
gcov_type_ptr, gcov_type_node,
NULL_TREE);
tree_pow2_profiler_fn = build_fn_decl ("__gcov_pow2_profiler",
pow2_profiler_fn_type);
one_value_profiler_fn_type
= build_function_type_list (void_type_node,
gcov_type_ptr, gcov_type_node,
NULL_TREE);
tree_one_value_profiler_fn
= build_fn_decl ("__gcov_one_value_profiler",
one_value_profiler_fn_type);
}
}
static void
tree_gen_edge_profiler (int edgeno, edge e)
{
tree tmp1 = create_tmp_var (gcov_type_node, "PROF");
tree tmp2 = create_tmp_var (gcov_type_node, "PROF");
tree ref = tree_coverage_counter_ref (GCOV_COUNTER_ARCS, edgeno);
tree stmt1 = build2 (MODIFY_EXPR, gcov_type_node, tmp1, ref);
tree stmt2 = build2 (MODIFY_EXPR, gcov_type_node, tmp2,
build2 (PLUS_EXPR, gcov_type_node,
tmp1, integer_one_node));
tree stmt3 = build2 (MODIFY_EXPR, gcov_type_node, ref, tmp2);
bsi_insert_on_edge (e, stmt1);
bsi_insert_on_edge (e, stmt2);
bsi_insert_on_edge (e, stmt3);
}
static tree
prepare_instrumented_value (block_stmt_iterator *bsi,
histogram_value value)
{
tree val = value->hvalue.value;
return force_gimple_operand_bsi (bsi, fold_convert (gcov_type_node, val),
true, NULL_TREE);
}
static void
tree_gen_interval_profiler (histogram_value value, unsigned tag, unsigned base)
{
tree stmt = value->hvalue.stmt;
block_stmt_iterator bsi = bsi_for_stmt (stmt);
tree ref = tree_coverage_counter_ref (tag, base), ref_ptr;
tree args, call, val;
tree start = build_int_cst_type (integer_type_node, value->hdata.intvl.int_start);
tree steps = build_int_cst_type (unsigned_type_node, value->hdata.intvl.steps);
ref_ptr = force_gimple_operand_bsi (&bsi,
build_addr (ref, current_function_decl),
true, NULL_TREE);
val = prepare_instrumented_value (&bsi, value);
args = tree_cons (NULL_TREE, ref_ptr,
tree_cons (NULL_TREE, val,
tree_cons (NULL_TREE, start,
tree_cons (NULL_TREE, steps,
NULL_TREE))));
call = build_function_call_expr (tree_interval_profiler_fn, args);
bsi_insert_before (&bsi, call, BSI_SAME_STMT);
}
static void
tree_gen_pow2_profiler (histogram_value value, unsigned tag, unsigned base)
{
tree stmt = value->hvalue.stmt;
block_stmt_iterator bsi = bsi_for_stmt (stmt);
tree ref = tree_coverage_counter_ref (tag, base), ref_ptr;
tree args, call, val;
ref_ptr = force_gimple_operand_bsi (&bsi,
build_addr (ref, current_function_decl),
true, NULL_TREE);
val = prepare_instrumented_value (&bsi, value);
args = tree_cons (NULL_TREE, ref_ptr,
tree_cons (NULL_TREE, val,
NULL_TREE));
call = build_function_call_expr (tree_pow2_profiler_fn, args);
bsi_insert_before (&bsi, call, BSI_SAME_STMT);
}
static void
tree_gen_one_value_profiler (histogram_value value, unsigned tag, unsigned base)
{
tree stmt = value->hvalue.stmt;
block_stmt_iterator bsi = bsi_for_stmt (stmt);
tree ref = tree_coverage_counter_ref (tag, base), ref_ptr;
tree args, call, val;
ref_ptr = force_gimple_operand_bsi (&bsi,
build_addr (ref, current_function_decl),
true, NULL_TREE);
val = prepare_instrumented_value (&bsi, value);
args = tree_cons (NULL_TREE, ref_ptr,
tree_cons (NULL_TREE, val,
NULL_TREE));
call = build_function_call_expr (tree_one_value_profiler_fn, args);
bsi_insert_before (&bsi, call, BSI_SAME_STMT);
}
static void
tree_gen_const_delta_profiler (histogram_value value ATTRIBUTE_UNUSED,
unsigned tag ATTRIBUTE_UNUSED,
unsigned base ATTRIBUTE_UNUSED)
{
#ifdef ENABLE_CHECKING
internal_error ("unimplemented functionality");
#endif
gcc_unreachable ();
}
static bool
do_tree_profiling (void)
{
if (profile_arc_flag || flag_test_coverage || flag_branch_probabilities)
{
tree_register_profile_hooks ();
tree_register_value_prof_hooks ();
return true;
}
return false;
}
static unsigned int
tree_profiling (void)
{
branch_prob ();
if (flag_branch_probabilities
&& flag_profile_values
&& flag_value_profile_transformations)
value_profile_transformations ();
free_dominance_info (CDI_DOMINATORS);
free_dominance_info (CDI_POST_DOMINATORS);
return 0;
}
struct tree_opt_pass pass_tree_profile =
{
"tree_profile",
do_tree_profiling,
tree_profiling,
NULL,
NULL,
0,
TV_BRANCH_PROB,
PROP_gimple_leh | PROP_cfg,
PROP_gimple_leh | PROP_cfg,
0,
0,
TODO_verify_stmts,
0
};
static bool
do_early_tree_profiling (void)
{
return (do_tree_profiling () && (!flag_unit_at_a_time || !optimize));
}
struct tree_opt_pass pass_early_tree_profile =
{
"early_tree_profile",
do_early_tree_profiling,
tree_profiling,
NULL,
NULL,
0,
TV_BRANCH_PROB,
PROP_gimple_leh | PROP_cfg,
PROP_gimple_leh | PROP_cfg,
0,
0,
TODO_verify_stmts,
0
};
struct profile_hooks tree_profile_hooks =
{
tree_init_edge_profiler,
tree_gen_edge_profiler,
tree_gen_interval_profiler,
tree_gen_pow2_profiler,
tree_gen_one_value_profiler,
tree_gen_const_delta_profiler
};
#include "gt-tree-profile.h"