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:
Martin Liska 2018-10-04 14:41:14 +02:00 committed by Martin Liska
parent 668f8d4526
commit 3edbcdbead
6 changed files with 93 additions and 60 deletions

View File

@ -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

View File

@ -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,

View File

@ -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);

View File

@ -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.

View File

@ -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

View File

@ -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;