Fix divergence in indirect profiling (PR gcov-profile/84107).
2018-10-04 Martin Liska <mliska@suse.cz> PR gcov-profile/84107 * tree-profile.c (init_ic_make_global_vars): Remove ic_void_ptr_var and ic_gcov_type_ptr_var. Come up with new ic_tuple* variables. Emit __gcov_indirect_call{,_topn} variables. (gimple_gen_ic_profiler): Access the variable and emit gimple. (gimple_gen_ic_func_profiler): Access __gcov_indirect_call.callee field. (gimple_init_gcov_profiler): Use ptr_type_node. * value-prof.c (gimple_ic): Use ptr_type_node. 2018-10-04 Martin Liska <mliska@suse.cz> PR gcov-profile/84107 * libgcov-profiler.c (__gcov_indirect_call): Change type to indirect_call_tuple. (struct indirect_call_tuple): New struct. (__gcov_indirect_call_topn_profiler): Change type. (__gcov_indirect_call_profiler_v2): Use the new variables. * libgcov.h (struct indirect_call_tuple): New struct definition. From-SVN: r264840
This commit is contained in:
parent
668f8d4526
commit
3edbcdbead
|
@ -1,3 +1,17 @@
|
||||||
|
2018-10-04 Martin Liska <mliska@suse.cz>
|
||||||
|
|
||||||
|
PR gcov-profile/84107
|
||||||
|
* tree-profile.c (init_ic_make_global_vars):
|
||||||
|
Remove ic_void_ptr_var and ic_gcov_type_ptr_var.
|
||||||
|
Come up with new ic_tuple* variables. Emit
|
||||||
|
__gcov_indirect_call{,_topn} variables.
|
||||||
|
(gimple_gen_ic_profiler): Access the variable
|
||||||
|
and emit gimple.
|
||||||
|
(gimple_gen_ic_func_profiler): Access
|
||||||
|
__gcov_indirect_call.callee field.
|
||||||
|
(gimple_init_gcov_profiler): Use ptr_type_node.
|
||||||
|
* value-prof.c (gimple_ic): Use ptr_type_node.
|
||||||
|
|
||||||
2018-10-04 Prathamesh Kulkarni <prathamesh.kulkarni@linaro.org>
|
2018-10-04 Prathamesh Kulkarni <prathamesh.kulkarni@linaro.org>
|
||||||
|
|
||||||
PR tree-optimization/85787
|
PR tree-optimization/85787
|
||||||
|
|
|
@ -53,6 +53,8 @@ along with GCC; see the file COPYING3. If not see
|
||||||
#include "stringpool.h"
|
#include "stringpool.h"
|
||||||
#include "attribs.h"
|
#include "attribs.h"
|
||||||
#include "tree-pretty-print.h"
|
#include "tree-pretty-print.h"
|
||||||
|
#include "langhooks.h"
|
||||||
|
#include "stor-layout.h"
|
||||||
|
|
||||||
static GTY(()) tree gcov_type_node;
|
static GTY(()) tree gcov_type_node;
|
||||||
static GTY(()) tree tree_interval_profiler_fn;
|
static GTY(()) tree tree_interval_profiler_fn;
|
||||||
|
@ -64,9 +66,9 @@ static GTY(()) tree tree_ior_profiler_fn;
|
||||||
static GTY(()) tree tree_time_profiler_counter;
|
static GTY(()) tree tree_time_profiler_counter;
|
||||||
|
|
||||||
|
|
||||||
static GTY(()) tree ic_void_ptr_var;
|
static GTY(()) tree ic_tuple_var;
|
||||||
static GTY(()) tree ic_gcov_type_ptr_var;
|
static GTY(()) tree ic_tuple_counters_field;
|
||||||
static GTY(()) tree ptr_void;
|
static GTY(()) tree ic_tuple_callee_field;
|
||||||
|
|
||||||
/* Do initialization work for the edge profiler. */
|
/* Do initialization work for the edge profiler. */
|
||||||
|
|
||||||
|
@ -80,39 +82,35 @@ init_ic_make_global_vars (void)
|
||||||
{
|
{
|
||||||
tree gcov_type_ptr;
|
tree gcov_type_ptr;
|
||||||
|
|
||||||
ptr_void = build_pointer_type (void_type_node);
|
|
||||||
|
|
||||||
ic_void_ptr_var
|
|
||||||
= build_decl (UNKNOWN_LOCATION, VAR_DECL,
|
|
||||||
get_identifier (
|
|
||||||
(PARAM_VALUE (PARAM_INDIR_CALL_TOPN_PROFILE) ?
|
|
||||||
"__gcov_indirect_call_topn_callee" :
|
|
||||||
"__gcov_indirect_call_callee")),
|
|
||||||
ptr_void);
|
|
||||||
TREE_PUBLIC (ic_void_ptr_var) = 1;
|
|
||||||
DECL_EXTERNAL (ic_void_ptr_var) = 1;
|
|
||||||
TREE_STATIC (ic_void_ptr_var) = 1;
|
|
||||||
DECL_ARTIFICIAL (ic_void_ptr_var) = 1;
|
|
||||||
DECL_INITIAL (ic_void_ptr_var) = NULL;
|
|
||||||
if (targetm.have_tls)
|
|
||||||
set_decl_tls_model (ic_void_ptr_var, decl_default_tls_model (ic_void_ptr_var));
|
|
||||||
|
|
||||||
gcov_type_ptr = build_pointer_type (get_gcov_type ());
|
gcov_type_ptr = build_pointer_type (get_gcov_type ());
|
||||||
|
|
||||||
ic_gcov_type_ptr_var
|
tree tuple_type = lang_hooks.types.make_type (RECORD_TYPE);
|
||||||
|
|
||||||
|
/* callee */
|
||||||
|
ic_tuple_callee_field = build_decl (BUILTINS_LOCATION, FIELD_DECL, NULL_TREE,
|
||||||
|
ptr_type_node);
|
||||||
|
|
||||||
|
/* counters */
|
||||||
|
ic_tuple_counters_field = build_decl (BUILTINS_LOCATION, FIELD_DECL,
|
||||||
|
NULL_TREE, gcov_type_ptr);
|
||||||
|
DECL_CHAIN (ic_tuple_counters_field) = ic_tuple_callee_field;
|
||||||
|
|
||||||
|
finish_builtin_struct (tuple_type, "indirect_call_tuple",
|
||||||
|
ic_tuple_counters_field, NULL_TREE);
|
||||||
|
|
||||||
|
ic_tuple_var
|
||||||
= build_decl (UNKNOWN_LOCATION, VAR_DECL,
|
= build_decl (UNKNOWN_LOCATION, VAR_DECL,
|
||||||
get_identifier (
|
get_identifier (
|
||||||
(PARAM_VALUE (PARAM_INDIR_CALL_TOPN_PROFILE) ?
|
(PARAM_VALUE (PARAM_INDIR_CALL_TOPN_PROFILE) ?
|
||||||
"__gcov_indirect_call_topn_counters" :
|
"__gcov_indirect_call_topn" :
|
||||||
"__gcov_indirect_call_counters")),
|
"__gcov_indirect_call")),
|
||||||
gcov_type_ptr);
|
tuple_type);
|
||||||
TREE_PUBLIC (ic_gcov_type_ptr_var) = 1;
|
TREE_PUBLIC (ic_tuple_var) = 1;
|
||||||
DECL_EXTERNAL (ic_gcov_type_ptr_var) = 1;
|
DECL_ARTIFICIAL (ic_tuple_var) = 1;
|
||||||
TREE_STATIC (ic_gcov_type_ptr_var) = 1;
|
DECL_INITIAL (ic_tuple_var) = NULL;
|
||||||
DECL_ARTIFICIAL (ic_gcov_type_ptr_var) = 1;
|
DECL_EXTERNAL (ic_tuple_var) = 1;
|
||||||
DECL_INITIAL (ic_gcov_type_ptr_var) = NULL;
|
|
||||||
if (targetm.have_tls)
|
if (targetm.have_tls)
|
||||||
set_decl_tls_model (ic_gcov_type_ptr_var, decl_default_tls_model (ic_gcov_type_ptr_var));
|
set_decl_tls_model (ic_tuple_var, decl_default_tls_model (tuple_type));
|
||||||
}
|
}
|
||||||
|
|
||||||
/* Create the type and function decls for the interface with gcov. */
|
/* Create the type and function decls for the interface with gcov. */
|
||||||
|
@ -185,7 +183,7 @@ gimple_init_gcov_profiler (void)
|
||||||
ic_profiler_fn_type
|
ic_profiler_fn_type
|
||||||
= build_function_type_list (void_type_node,
|
= build_function_type_list (void_type_node,
|
||||||
gcov_type_node,
|
gcov_type_node,
|
||||||
ptr_void,
|
ptr_type_node,
|
||||||
NULL_TREE);
|
NULL_TREE);
|
||||||
profiler_fn_name = "__gcov_indirect_call_profiler_v2";
|
profiler_fn_name = "__gcov_indirect_call_profiler_v2";
|
||||||
if (PARAM_VALUE (PARAM_INDIR_CALL_TOPN_PROFILE))
|
if (PARAM_VALUE (PARAM_INDIR_CALL_TOPN_PROFILE))
|
||||||
|
@ -388,22 +386,29 @@ gimple_gen_ic_profiler (histogram_value value, unsigned tag, unsigned base)
|
||||||
|
|
||||||
/* Insert code:
|
/* Insert code:
|
||||||
|
|
||||||
stmt1: __gcov_indirect_call_counters = get_relevant_counter_ptr ();
|
stmt1: __gcov_indirect_call.counters = get_relevant_counter_ptr ();
|
||||||
stmt2: tmp1 = (void *) (indirect call argument value)
|
stmt2: tmp1 = (void *) (indirect call argument value)
|
||||||
stmt3: __gcov_indirect_call_callee = tmp1;
|
stmt3: __gcov_indirect_call.callee = tmp1;
|
||||||
|
|
||||||
Example:
|
Example:
|
||||||
f_1 = foo;
|
f_1 = foo;
|
||||||
__gcov_indirect_call_counters = &__gcov4.main[0];
|
__gcov_indirect_call.counters = &__gcov4.main[0];
|
||||||
PROF_9 = f_1;
|
PROF_9 = f_1;
|
||||||
__gcov_indirect_call_callee = PROF_9;
|
__gcov_indirect_call_callee = PROF_9;
|
||||||
_4 = f_1 ();
|
_4 = f_1 ();
|
||||||
*/
|
*/
|
||||||
|
|
||||||
stmt1 = gimple_build_assign (ic_gcov_type_ptr_var, ref_ptr);
|
tree gcov_type_ptr = build_pointer_type (get_gcov_type ());
|
||||||
tmp1 = make_temp_ssa_name (ptr_void, NULL, "PROF");
|
|
||||||
|
tree counter_ref = build3 (COMPONENT_REF, gcov_type_ptr,
|
||||||
|
ic_tuple_var, ic_tuple_counters_field, NULL_TREE);
|
||||||
|
|
||||||
|
stmt1 = gimple_build_assign (counter_ref, ref_ptr);
|
||||||
|
tmp1 = make_temp_ssa_name (ptr_type_node, NULL, "PROF");
|
||||||
stmt2 = gimple_build_assign (tmp1, unshare_expr (value->hvalue.value));
|
stmt2 = gimple_build_assign (tmp1, unshare_expr (value->hvalue.value));
|
||||||
stmt3 = gimple_build_assign (ic_void_ptr_var, gimple_assign_lhs (stmt2));
|
tree callee_ref = build3 (COMPONENT_REF, ptr_type_node,
|
||||||
|
ic_tuple_var, ic_tuple_callee_field, NULL_TREE);
|
||||||
|
stmt3 = gimple_build_assign (callee_ref, tmp1);
|
||||||
|
|
||||||
gsi_insert_before (&gsi, stmt1, GSI_SAME_STMT);
|
gsi_insert_before (&gsi, stmt1, GSI_SAME_STMT);
|
||||||
gsi_insert_before (&gsi, stmt2, GSI_SAME_STMT);
|
gsi_insert_before (&gsi, stmt2, GSI_SAME_STMT);
|
||||||
|
@ -459,9 +464,12 @@ gimple_gen_ic_func_profiler (void)
|
||||||
resetting __gcov_indirect_call_callee to NULL. */
|
resetting __gcov_indirect_call_callee to NULL. */
|
||||||
|
|
||||||
gimple_stmt_iterator gsi = gsi_start_bb (cond_bb);
|
gimple_stmt_iterator gsi = gsi_start_bb (cond_bb);
|
||||||
void0 = build_int_cst (build_pointer_type (void_type_node), 0);
|
void0 = build_int_cst (ptr_type_node, 0);
|
||||||
|
|
||||||
tree ref = force_gimple_operand_gsi (&gsi, ic_void_ptr_var, true, NULL_TREE,
|
tree callee_ref = build3 (COMPONENT_REF, ptr_type_node,
|
||||||
|
ic_tuple_var, ic_tuple_callee_field, NULL_TREE);
|
||||||
|
|
||||||
|
tree ref = force_gimple_operand_gsi (&gsi, callee_ref, true, NULL_TREE,
|
||||||
true, GSI_SAME_STMT);
|
true, GSI_SAME_STMT);
|
||||||
|
|
||||||
gcond *cond = gimple_build_cond (NE_EXPR, ref,
|
gcond *cond = gimple_build_cond (NE_EXPR, ref,
|
||||||
|
|
|
@ -1290,7 +1290,6 @@ gimple_ic (gcall *icall_stmt, struct cgraph_node *direct_call,
|
||||||
gcond *cond_stmt;
|
gcond *cond_stmt;
|
||||||
tree tmp0, tmp1, tmp;
|
tree tmp0, tmp1, tmp;
|
||||||
basic_block cond_bb, dcall_bb, icall_bb, join_bb = NULL;
|
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;
|
edge e_cd, e_ci, e_di, e_dj = NULL, e_ij;
|
||||||
gimple_stmt_iterator gsi;
|
gimple_stmt_iterator gsi;
|
||||||
int lp_nr, dflags;
|
int lp_nr, dflags;
|
||||||
|
@ -1300,13 +1299,13 @@ gimple_ic (gcall *icall_stmt, struct cgraph_node *direct_call,
|
||||||
cond_bb = gimple_bb (icall_stmt);
|
cond_bb = gimple_bb (icall_stmt);
|
||||||
gsi = gsi_for_stmt (icall_stmt);
|
gsi = gsi_for_stmt (icall_stmt);
|
||||||
|
|
||||||
tmp0 = make_temp_ssa_name (optype, NULL, "PROF");
|
tmp0 = make_temp_ssa_name (ptr_type_node, NULL, "PROF");
|
||||||
tmp1 = make_temp_ssa_name (optype, NULL, "PROF");
|
tmp1 = make_temp_ssa_name (ptr_type_node, NULL, "PROF");
|
||||||
tmp = unshare_expr (gimple_call_fn (icall_stmt));
|
tmp = unshare_expr (gimple_call_fn (icall_stmt));
|
||||||
load_stmt = gimple_build_assign (tmp0, tmp);
|
load_stmt = gimple_build_assign (tmp0, tmp);
|
||||||
gsi_insert_before (&gsi, load_stmt, GSI_SAME_STMT);
|
gsi_insert_before (&gsi, load_stmt, GSI_SAME_STMT);
|
||||||
|
|
||||||
tmp = fold_convert (optype, build_addr (direct_call->decl));
|
tmp = fold_convert (ptr_type_node, build_addr (direct_call->decl));
|
||||||
load_stmt = gimple_build_assign (tmp1, tmp);
|
load_stmt = gimple_build_assign (tmp1, tmp);
|
||||||
gsi_insert_before (&gsi, load_stmt, GSI_SAME_STMT);
|
gsi_insert_before (&gsi, load_stmt, GSI_SAME_STMT);
|
||||||
|
|
||||||
|
|
|
@ -1,3 +1,15 @@
|
||||||
|
2018-10-04 Martin Liska <mliska@suse.cz>
|
||||||
|
|
||||||
|
PR gcov-profile/84107
|
||||||
|
* libgcov-profiler.c (__gcov_indirect_call):
|
||||||
|
Change type to indirect_call_tuple.
|
||||||
|
(struct indirect_call_tuple): New struct.
|
||||||
|
(__gcov_indirect_call_topn_profiler): Change type.
|
||||||
|
(__gcov_indirect_call_profiler_v2): Use the new
|
||||||
|
variables.
|
||||||
|
* libgcov.h (struct indirect_call_tuple): New struct
|
||||||
|
definition.
|
||||||
|
|
||||||
2018-10-03 Uros Bizjak <ubizjak@gmail.com>
|
2018-10-03 Uros Bizjak <ubizjak@gmail.com>
|
||||||
|
|
||||||
* libgcc2.c (isnan): Use __builtin_isnan.
|
* libgcc2.c (isnan): Use __builtin_isnan.
|
||||||
|
|
|
@ -271,12 +271,7 @@ __gcov_topn_value_profiler_body (gcov_type *counters, gcov_type value)
|
||||||
#if defined(HAVE_CC_TLS) && !defined (USE_EMUTLS)
|
#if defined(HAVE_CC_TLS) && !defined (USE_EMUTLS)
|
||||||
__thread
|
__thread
|
||||||
#endif
|
#endif
|
||||||
gcov_type *__gcov_indirect_call_topn_counters ATTRIBUTE_HIDDEN;
|
struct indirect_call_tuple __gcov_indirect_call_topn;
|
||||||
|
|
||||||
#if defined(HAVE_CC_TLS) && !defined (USE_EMUTLS)
|
|
||||||
__thread
|
|
||||||
#endif
|
|
||||||
void *__gcov_indirect_call_topn_callee ATTRIBUTE_HIDDEN;
|
|
||||||
|
|
||||||
#ifdef TARGET_VTABLE_USES_DESCRIPTORS
|
#ifdef TARGET_VTABLE_USES_DESCRIPTORS
|
||||||
#define VTABLE_USES_DESCRIPTORS 1
|
#define VTABLE_USES_DESCRIPTORS 1
|
||||||
|
@ -290,14 +285,14 @@ void *__gcov_indirect_call_topn_callee ATTRIBUTE_HIDDEN;
|
||||||
void
|
void
|
||||||
__gcov_indirect_call_topn_profiler (gcov_type value, void* cur_func)
|
__gcov_indirect_call_topn_profiler (gcov_type value, void* cur_func)
|
||||||
{
|
{
|
||||||
void *callee_func = __gcov_indirect_call_topn_callee;
|
void *callee_func = __gcov_indirect_call_topn.callee;
|
||||||
/* If the C++ virtual tables contain function descriptors then one
|
/* If the C++ virtual tables contain function descriptors then one
|
||||||
function may have multiple descriptors and we need to dereference
|
function may have multiple descriptors and we need to dereference
|
||||||
the descriptors to see if they point to the same function. */
|
the descriptors to see if they point to the same function. */
|
||||||
if (cur_func == callee_func
|
if (cur_func == callee_func
|
||||||
|| (VTABLE_USES_DESCRIPTORS && callee_func
|
|| (VTABLE_USES_DESCRIPTORS && callee_func
|
||||||
&& *(void **) cur_func == *(void **) callee_func))
|
&& *(void **) cur_func == *(void **) callee_func))
|
||||||
__gcov_topn_value_profiler_body (__gcov_indirect_call_topn_counters, value);
|
__gcov_topn_value_profiler_body (__gcov_indirect_call_topn.counters, value);
|
||||||
}
|
}
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
|
@ -311,11 +306,7 @@ __gcov_indirect_call_topn_profiler (gcov_type value, void* cur_func)
|
||||||
#if defined(HAVE_CC_TLS) && !defined (USE_EMUTLS)
|
#if defined(HAVE_CC_TLS) && !defined (USE_EMUTLS)
|
||||||
__thread
|
__thread
|
||||||
#endif
|
#endif
|
||||||
void * __gcov_indirect_call_callee;
|
struct indirect_call_tuple __gcov_indirect_call;
|
||||||
#if defined(HAVE_CC_TLS) && !defined (USE_EMUTLS)
|
|
||||||
__thread
|
|
||||||
#endif
|
|
||||||
gcov_type * __gcov_indirect_call_counters;
|
|
||||||
|
|
||||||
/* By default, the C++ compiler will use function addresses in the
|
/* By default, the C++ compiler will use function addresses in the
|
||||||
vtable entries. Setting TARGET_VTABLE_USES_DESCRIPTORS to nonzero
|
vtable entries. Setting TARGET_VTABLE_USES_DESCRIPTORS to nonzero
|
||||||
|
@ -332,12 +323,12 @@ __gcov_indirect_call_profiler_v2 (gcov_type value, void* cur_func)
|
||||||
/* If the C++ virtual tables contain function descriptors then one
|
/* If the C++ virtual tables contain function descriptors then one
|
||||||
function may have multiple descriptors and we need to dereference
|
function may have multiple descriptors and we need to dereference
|
||||||
the descriptors to see if they point to the same function. */
|
the descriptors to see if they point to the same function. */
|
||||||
if (cur_func == __gcov_indirect_call_callee
|
if (cur_func == __gcov_indirect_call.callee
|
||||||
|| (__LIBGCC_VTABLE_USES_DESCRIPTORS__
|
|| (__LIBGCC_VTABLE_USES_DESCRIPTORS__
|
||||||
&& *(void **) cur_func == *(void **) __gcov_indirect_call_callee))
|
&& *(void **) cur_func == *(void **) __gcov_indirect_call.callee))
|
||||||
__gcov_one_value_profiler_body (__gcov_indirect_call_counters, value, 0);
|
__gcov_one_value_profiler_body (__gcov_indirect_call.counters, value, 0);
|
||||||
|
|
||||||
__gcov_indirect_call_callee = NULL;
|
__gcov_indirect_call.callee = NULL;
|
||||||
}
|
}
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
|
|
|
@ -227,6 +227,15 @@ struct gcov_master
|
||||||
struct gcov_root *root;
|
struct gcov_root *root;
|
||||||
};
|
};
|
||||||
|
|
||||||
|
struct indirect_call_tuple
|
||||||
|
{
|
||||||
|
/* Callee function. */
|
||||||
|
void *callee;
|
||||||
|
|
||||||
|
/* Pointer to counters. */
|
||||||
|
gcov_type *counters;
|
||||||
|
};
|
||||||
|
|
||||||
/* Exactly one of these will be active in the process. */
|
/* Exactly one of these will be active in the process. */
|
||||||
extern struct gcov_master __gcov_master;
|
extern struct gcov_master __gcov_master;
|
||||||
|
|
||||||
|
|
Loading…
Reference in New Issue