/* Transformations based on profile information for values.
- Copyright (C) 2003, 2004, 2005, 2006, 2007, 2008, 2009, 2010, 2011, 2012
- Free Software Foundation, Inc.
+ Copyright (C) 2003-2013 Free Software Foundation, Inc.
This file is part of GCC.
#include "dumpfile.h"
#include "pointer-set.h"
#include "profile.h"
+#include "data-streamer.h"
/* In this file value profile based optimizations are placed. Currently the
following optimizations are implemented (for more detailed descriptions
to profile. There are different histogram types (see HIST_TYPE_* in
value-prof.h) and each transformation can request one or more histogram
types per GIMPLE statement. The function gimple_find_values_to_profile()
- collects the values to profile in a VEC, and adds the number of counters
+ collects the values to profile in a vec, and adds the number of counters
required for the different histogram types.
For a -fprofile-generate run, the statements for which values should be
}
fprintf (dump_file, ".\n");
break;
+ case HIST_TYPE_MAX:
+ gcc_unreachable ();
}
}
+/* Dump information about HIST to DUMP_FILE. */
+
+void
+stream_out_histogram_value (struct output_block *ob, histogram_value hist)
+{
+ struct bitpack_d bp;
+ unsigned int i;
+
+ bp = bitpack_create (ob->main_stream);
+ bp_pack_enum (&bp, hist_type, HIST_TYPE_MAX, hist->type);
+ bp_pack_value (&bp, hist->hvalue.next != NULL, 1);
+ streamer_write_bitpack (&bp);
+ switch (hist->type)
+ {
+ case HIST_TYPE_INTERVAL:
+ streamer_write_hwi (ob, hist->hdata.intvl.int_start);
+ streamer_write_uhwi (ob, hist->hdata.intvl.steps);
+ break;
+ default:
+ break;
+ }
+ for (i = 0; i < hist->n_counters; i++)
+ streamer_write_gcov_count (ob, hist->hvalue.counters[i]);
+ if (hist->hvalue.next)
+ stream_out_histogram_value (ob, hist->hvalue.next);
+}
+/* Dump information about HIST to DUMP_FILE. */
+
+void
+stream_in_histogram_value (struct lto_input_block *ib, gimple stmt)
+{
+ enum hist_type type;
+ unsigned int ncounters = 0;
+ struct bitpack_d bp;
+ unsigned int i;
+ histogram_value new_val;
+ bool next;
+ histogram_value *next_p = NULL;
+
+ do
+ {
+ bp = streamer_read_bitpack (ib);
+ type = bp_unpack_enum (&bp, hist_type, HIST_TYPE_MAX);
+ next = bp_unpack_value (&bp, 1);
+ new_val = gimple_alloc_histogram_value (cfun, type, stmt, NULL);
+ switch (type)
+ {
+ case HIST_TYPE_INTERVAL:
+ new_val->hdata.intvl.int_start = streamer_read_hwi (ib);
+ new_val->hdata.intvl.steps = streamer_read_uhwi (ib);
+ ncounters = new_val->hdata.intvl.steps + 2;
+ break;
+
+ case HIST_TYPE_POW2:
+ case HIST_TYPE_AVERAGE:
+ ncounters = 2;
+ break;
+
+ case HIST_TYPE_SINGLE_VALUE:
+ case HIST_TYPE_INDIR_CALL:
+ ncounters = 3;
+ break;
+
+ case HIST_TYPE_CONST_DELTA:
+ ncounters = 4;
+ break;
+
+ case HIST_TYPE_IOR:
+ ncounters = 1;
+ break;
+ case HIST_TYPE_MAX:
+ gcc_unreachable ();
+ }
+ new_val->hvalue.counters = XNEWVAR (gcov_type, sizeof (*new_val->hvalue.counters) * ncounters);
+ new_val->n_counters = ncounters;
+ for (i = 0; i < ncounters; i++)
+ new_val->hvalue.counters[i] = streamer_read_gcov_count (ib);
+ if (!next_p)
+ gimple_add_histogram_value (cfun, stmt, new_val);
+ else
+ *next_p = new_val;
+ next_p = &new_val->hvalue.next;
+ }
+ while (next);
+}
+
/* Dump all histograms attached to STMT to DUMP_FILE. */
void
gcov_type all)
{
gimple stmt1, stmt2, stmt3;
- tree tmp0, tmp1, tmp2, tmpv;
+ tree tmp0, tmp1, tmp2;
gimple bb1end, bb2end, bb3end;
basic_block bb, bb2, bb3, bb4;
tree optype, op1, op2;
bb = gimple_bb (stmt);
gsi = gsi_for_stmt (stmt);
- tmpv = create_tmp_reg (optype, "PROF");
- tmp0 = make_ssa_name (tmpv, NULL);
- tmp1 = make_ssa_name (tmpv, NULL);
+ tmp0 = make_temp_ssa_name (optype, NULL, "PROF");
+ tmp1 = make_temp_ssa_name (optype, NULL, "PROF");
stmt1 = gimple_build_assign (tmp0, fold_convert (optype, value));
- SSA_NAME_DEF_STMT (tmp0) = stmt1;
stmt2 = gimple_build_assign (tmp1, op2);
- SSA_NAME_DEF_STMT (tmp1) = stmt2;
stmt3 = gimple_build_cond (NE_EXPR, tmp1, tmp0, NULL_TREE, NULL_TREE);
gsi_insert_before (&gsi, stmt1, GSI_SAME_STMT);
gsi_insert_before (&gsi, stmt2, GSI_SAME_STMT);
/* Compute probability of taking the optimal path. */
if (all > 0)
- prob = (count * REG_BR_PROB_BASE + all / 2) / all;
+ prob = GCOV_COMPUTE_SCALE (count, all);
else
prob = 0;
gimple_mod_pow2 (gimple stmt, int prob, gcov_type count, gcov_type all)
{
gimple stmt1, stmt2, stmt3, stmt4;
- tree tmp2, tmp3, tmpv;
+ tree tmp2, tmp3;
gimple bb1end, bb2end, bb3end;
basic_block bb, bb2, bb3, bb4;
tree optype, op1, op2;
gsi = gsi_for_stmt (stmt);
result = create_tmp_reg (optype, "PROF");
- tmpv = create_tmp_var (optype, "PROF");
- tmp2 = make_ssa_name (tmpv, NULL);
- tmp3 = make_ssa_name (tmpv, NULL);
+ tmp2 = make_temp_ssa_name (optype, NULL, "PROF");
+ tmp3 = make_temp_ssa_name (optype, NULL, "PROF");
stmt2 = gimple_build_assign_with_ops (PLUS_EXPR, tmp2, op2,
build_int_cst (optype, -1));
- SSA_NAME_DEF_STMT (tmp2) = stmt2;
stmt3 = gimple_build_assign_with_ops (BIT_AND_EXPR, tmp3, tmp2, op2);
- SSA_NAME_DEF_STMT (tmp3) = stmt3;
stmt4 = gimple_build_cond (NE_EXPR, tmp3, build_int_cst (optype, 0),
NULL_TREE, NULL_TREE);
gsi_insert_before (&gsi, stmt2, GSI_SAME_STMT);
return false;
if (all > 0)
- prob = (count * REG_BR_PROB_BASE + all / 2) / all;
+ prob = GCOV_COMPUTE_SCALE (count, all);
else
prob = 0;
gsi = gsi_for_stmt (stmt);
result = create_tmp_reg (optype, "PROF");
- tmp1 = make_ssa_name (create_tmp_var (optype, "PROF"), NULL);
+ tmp1 = make_temp_ssa_name (optype, NULL, "PROF");
stmt1 = gimple_build_assign (result, op1);
stmt2 = gimple_build_assign (tmp1, op2);
- SSA_NAME_DEF_STMT (tmp1) = stmt2;
stmt3 = gimple_build_cond (LT_EXPR, result, tmp1, NULL_TREE, NULL_TREE);
gsi_insert_before (&gsi, stmt1, GSI_SAME_STMT);
gsi_insert_before (&gsi, stmt2, GSI_SAME_STMT);
/* Compute probability of taking the optimal path(s). */
if (all > 0)
{
- prob1 = (count1 * REG_BR_PROB_BASE + all / 2) / all;
- prob2 = (count2 * REG_BR_PROB_BASE + all / 2) / all;
+ prob1 = GCOV_COMPUTE_SCALE (count1, all);
+ prob2 = GCOV_COMPUTE_SCALE (count2, all);
}
else
{
return true;
}
-static VEC(cgraph_node_ptr, heap) *cgraph_node_map = NULL;
+static vec<cgraph_node_ptr> cgraph_node_map
+ = vNULL;
/* Initialize map from FUNCDEF_NO to CGRAPH_NODE. */
struct cgraph_node *n;
if (get_last_funcdef_no ())
- VEC_safe_grow_cleared (cgraph_node_ptr, heap,
- cgraph_node_map, get_last_funcdef_no ());
+ cgraph_node_map.safe_grow_cleared (get_last_funcdef_no ());
FOR_EACH_FUNCTION (n)
{
if (DECL_STRUCT_FUNCTION (n->symbol.decl))
- VEC_replace (cgraph_node_ptr, cgraph_node_map,
- DECL_STRUCT_FUNCTION (n->symbol.decl)->funcdef_no, n);
+ cgraph_node_map[DECL_STRUCT_FUNCTION (n->symbol.decl)->funcdef_no] = n;
}
}
void
del_node_map (void)
{
- VEC_free (cgraph_node_ptr, heap, cgraph_node_map);
- cgraph_node_map = NULL;
+ cgraph_node_map.release ();
}
/* Return cgraph node for function with pid */
find_func_by_funcdef_no (int func_id)
{
int max_id = get_last_funcdef_no ();
- if (func_id >= max_id || VEC_index (cgraph_node_ptr,
- cgraph_node_map,
- func_id) == NULL)
+ if (func_id >= max_id || cgraph_node_map[func_id] == NULL)
{
if (flag_profile_correction)
inform (DECL_SOURCE_LOCATION (current_function_decl),
return NULL;
}
- return VEC_index (cgraph_node_ptr, cgraph_node_map, func_id);
+ return cgraph_node_map[func_id];
}
/* Perform sanity check on the indirect call target. Due to race conditions,
check_ic_target (gimple call_stmt, struct cgraph_node *target)
{
location_t locus;
- if (gimple_check_call_matching_types (call_stmt, target->symbol.decl))
+ if (gimple_check_call_matching_types (call_stmt, target->symbol.decl, true))
return true;
locus = gimple_location (call_stmt);
int prob, gcov_type count, gcov_type all)
{
gimple dcall_stmt, load_stmt, cond_stmt;
- tree tmp0, tmp1, tmpv, tmp;
+ tree tmp0, tmp1, tmp;
basic_block cond_bb, dcall_bb, icall_bb, join_bb = NULL;
tree optype = build_pointer_type (void_type_node);
edge e_cd, e_ci, e_di, e_dj = NULL, e_ij;
cond_bb = gimple_bb (icall_stmt);
gsi = gsi_for_stmt (icall_stmt);
- tmpv = create_tmp_reg (optype, "PROF");
- tmp0 = make_ssa_name (tmpv, NULL);
- tmp1 = make_ssa_name (tmpv, NULL);
+ tmp0 = make_temp_ssa_name (optype, NULL, "PROF");
+ tmp1 = make_temp_ssa_name (optype, NULL, "PROF");
tmp = unshare_expr (gimple_call_fn (icall_stmt));
load_stmt = gimple_build_assign (tmp0, tmp);
- SSA_NAME_DEF_STMT (tmp0) = load_stmt;
gsi_insert_before (&gsi, load_stmt, GSI_SAME_STMT);
tmp = fold_convert (optype, build_addr (direct_call->symbol.decl,
current_function_decl));
load_stmt = gimple_build_assign (tmp1, tmp);
- SSA_NAME_DEF_STMT (tmp1) = load_stmt;
gsi_insert_before (&gsi, load_stmt, GSI_SAME_STMT);
cond_stmt = gimple_build_cond (EQ_EXPR, tmp1, tmp0, NULL_TREE, NULL_TREE);
{
tree result = gimple_call_lhs (icall_stmt);
gimple phi = create_phi_node (result, join_bb);
- SSA_NAME_DEF_STMT (result) = phi;
gimple_call_set_lhs (icall_stmt,
- make_ssa_name (SSA_NAME_VAR (result), icall_stmt));
+ duplicate_ssa_name (result, icall_stmt));
add_phi_arg (phi, gimple_call_lhs (icall_stmt), e_ij, UNKNOWN_LOCATION);
gimple_call_set_lhs (dcall_stmt,
- make_ssa_name (SSA_NAME_VAR (result), dcall_stmt));
+ duplicate_ssa_name (result, dcall_stmt));
add_phi_arg (phi, gimple_call_lhs (dcall_stmt), e_dj, UNKNOWN_LOCATION);
}
return false;
if (all > 0)
- prob = (count * REG_BR_PROB_BASE + all / 2) / all;
+ prob = GCOV_COMPUTE_SCALE (count, all);
else
prob = 0;
direct_call = find_func_by_funcdef_no ((int)val);
gcov_type count, gcov_type all)
{
gimple tmp_stmt, cond_stmt, icall_stmt;
- tree tmp0, tmp1, tmpv, vcall_size, optype;
+ tree tmp0, tmp1, vcall_size, optype;
basic_block cond_bb, icall_bb, vcall_bb, join_bb;
edge e_ci, e_cv, e_iv, e_ij, e_vj;
gimple_stmt_iterator gsi;
vcall_size = gimple_call_arg (vcall_stmt, size_arg);
optype = TREE_TYPE (vcall_size);
- tmpv = create_tmp_var (optype, "PROF");
- tmp0 = make_ssa_name (tmpv, NULL);
- tmp1 = make_ssa_name (tmpv, NULL);
+ tmp0 = make_temp_ssa_name (optype, NULL, "PROF");
+ tmp1 = make_temp_ssa_name (optype, NULL, "PROF");
tmp_stmt = gimple_build_assign (tmp0, fold_convert (optype, icall_size));
- SSA_NAME_DEF_STMT (tmp0) = tmp_stmt;
gsi_insert_before (&gsi, tmp_stmt, GSI_SAME_STMT);
tmp_stmt = gimple_build_assign (tmp1, vcall_size);
- SSA_NAME_DEF_STMT (tmp1) = tmp_stmt;
gsi_insert_before (&gsi, tmp_stmt, GSI_SAME_STMT);
cond_stmt = gimple_build_cond (EQ_EXPR, tmp1, tmp0, NULL_TREE, NULL_TREE);
{
tree result = gimple_call_lhs (vcall_stmt);
gimple phi = create_phi_node (result, join_bb);
- SSA_NAME_DEF_STMT (result) = phi;
gimple_call_set_lhs (vcall_stmt,
- make_ssa_name (SSA_NAME_VAR (result), vcall_stmt));
+ duplicate_ssa_name (result, vcall_stmt));
add_phi_arg (phi, gimple_call_lhs (vcall_stmt), e_vj, UNKNOWN_LOCATION);
gimple_call_set_lhs (icall_stmt,
- make_ssa_name (SSA_NAME_VAR (result), icall_stmt));
+ duplicate_ssa_name (result, icall_stmt));
add_phi_arg (phi, gimple_call_lhs (icall_stmt), e_ij, UNKNOWN_LOCATION);
}
if (check_counter (stmt, "value", &count, &all, gimple_bb (stmt)->count))
return false;
if (all > 0)
- prob = (count * REG_BR_PROB_BASE + all / 2) / all;
+ prob = GCOV_COMPUTE_SCALE (count, all);
else
prob = 0;
dest = gimple_call_arg (stmt, 0);
divisor = gimple_assign_rhs2 (stmt);
op0 = gimple_assign_rhs1 (stmt);
- VEC_reserve (histogram_value, heap, *values, 3);
+ values->reserve (3);
- if (is_gimple_reg (divisor))
+ if (TREE_CODE (divisor) == SSA_NAME)
/* Check for the case where the divisor is the same value most
of the time. */
- VEC_quick_push (histogram_value, *values,
- gimple_alloc_histogram_value (cfun,
+ values->quick_push (gimple_alloc_histogram_value (cfun,
HIST_TYPE_SINGLE_VALUE,
stmt, divisor));
{
tree val;
/* Check for a special case where the divisor is power of 2. */
- VEC_quick_push (histogram_value, *values,
- gimple_alloc_histogram_value (cfun, HIST_TYPE_POW2,
- stmt, divisor));
+ values->quick_push (gimple_alloc_histogram_value (cfun,
+ HIST_TYPE_POW2,
+ stmt, divisor));
val = build2 (TRUNC_DIV_EXPR, type, op0, divisor);
hist = gimple_alloc_histogram_value (cfun, HIST_TYPE_INTERVAL,
stmt, val);
hist->hdata.intvl.int_start = 0;
hist->hdata.intvl.steps = 2;
- VEC_quick_push (histogram_value, *values, hist);
+ values->quick_push (hist);
}
return;
callee = gimple_call_fn (stmt);
- VEC_reserve (histogram_value, heap, *values, 3);
+ values->reserve (3);
- VEC_quick_push (histogram_value, *values,
- gimple_alloc_histogram_value (cfun, HIST_TYPE_INDIR_CALL,
- stmt, callee));
+ values->quick_push (gimple_alloc_histogram_value (cfun, HIST_TYPE_INDIR_CALL,
+ stmt, callee));
return;
}
if (TREE_CODE (blck_size) != INTEGER_CST)
{
- VEC_safe_push (histogram_value, heap, *values,
- gimple_alloc_histogram_value (cfun, HIST_TYPE_SINGLE_VALUE,
- stmt, blck_size));
- VEC_safe_push (histogram_value, heap, *values,
- gimple_alloc_histogram_value (cfun, HIST_TYPE_AVERAGE,
- stmt, blck_size));
+ values->safe_push (gimple_alloc_histogram_value (cfun,
+ HIST_TYPE_SINGLE_VALUE,
+ stmt, blck_size));
+ values->safe_push (gimple_alloc_histogram_value (cfun, HIST_TYPE_AVERAGE,
+ stmt, blck_size));
}
if (TREE_CODE (blck_size) != INTEGER_CST)
- VEC_safe_push (histogram_value, heap, *values,
- gimple_alloc_histogram_value (cfun, HIST_TYPE_IOR,
- stmt, dest));
+ values->safe_push (gimple_alloc_histogram_value (cfun, HIST_TYPE_IOR,
+ stmt, dest));
}
/* Find values inside STMT for that we want to measure histograms and adds
unsigned i;
histogram_value hist = NULL;
- *values = NULL;
+ values->create (0);
FOR_EACH_BB (bb)
for (gsi = gsi_start_bb (bb); !gsi_end_p (gsi); gsi_next (&gsi))
gimple_values_to_profile (gsi_stmt (gsi), values);
- FOR_EACH_VEC_ELT (histogram_value, *values, i, hist)
+ FOR_EACH_VEC_ELT (*values, i, hist)
{
switch (hist->type)
{