This is the mail archive of the gcc-patches@gcc.gnu.org mailing list for the GCC project.


Index Nav: [Date Index] [Subject Index] [Author Index] [Thread Index]
Message Nav: [Date Prev] [Date Next] [Thread Prev] [Thread Next]
Other format: [Raw text]

Re: [PATCH PING, PR 46287] Do not generate direct calls to thunks


On Mon, Nov 22, 2010 at 10:44 PM, Martin Jambor <mjambor@suse.cz> wrote:
> Hi,
>
> I'd like to ping my patch from November 11th. ?Below is the original
> accompanying email and a refreshed version of the patch (it is exactly
> the same, just line numbers changed slightly). ?Further patches I am
> about to submit momentarily are based on this one so I'd really
> appreciate some progress with this one. ?I have re-bootstrapped and
> re-tested it on a current trunk today on x86-64-linux.
>
> Thanks,
>
> Martin
>
> ----------------------------------------------------------------------
>
> Hi,
>
> we currently cannot really represent direct calls to thunks in the
> call graph (i.e. in the edges) and this means we can omit the
> necessary thunk adjustments when using that edge in IPA
> transformations. ?This then causes problems filed as PR 46053 and PR
> 46287. ?In 4.5 there were no such calls so it did not matter but with
> devirtualization we currently have them and we either need to handle
> them or avoid them. ?The patch below does both.
>
> Certainly, soon we will need to be able to represent this information
> on the edges in the full generality. ?In particular we will have to
> once we start devirtualizing by folding loads from the VMT. ?However,
> dealing with result adjusting and virtual_offset adjusting thunks will
> require more changes than I am comfortable to push in stage three,
> mainly because they are nested but there will also be other unforseen
> problems too.
>
> Therefore, I currently handle the simple this adjustment thunks and
> punt when a more complex one is discovered. ?Calls to this adjusting
> thunks are then converted to a POINTER_PLUS in the caller and a call
> to the ordinary function declaration. ?This way, we still don't have
> any direct calls to thunks in the IL. ?These adjustments in callees
> are also performed during IPA inline and IPA-CP devirtualizations.
>
> I do not perform the thunk check if the second argument of a folded
> OBJ_TYPE_REF is an ADDR_EXPR of a simple declaration (as opposed to a
> COMPONENT_REF) so that g++.dg/opt/devirt1.C passes. ?If I did, the
> thunk test would not be possible because there is no call graph node
> for the called method (which is not defined in this compilation unit).
> In this case there should be no thunks involved ( it is not a call to
> an ancestor's virtual method) and it is what previous versions of gcc
> do so we should not regress.
>
> Bootstrapped and tested on x86-64-linux without any issues, a very
> similar patch has also passed make check-c++ on i686. ?OK for trunk?

Ok if Honza is ok with the cgraph changes.

Thanks,
Richard.

> Thanks,
>
> Martin
>
>
>
>
> 2010-11-08 ?Martin Jambor ?<mjambor@suse.cz>
>
> ? ? ? ?PR tree-optimization/46053
> ? ? ? ?PR middle-end/46287
> ? ? ? ?* cgraph.h (cgraph_indirect_call_info): New field.
> ? ? ? ?* gimple.h (gimple_fold_obj_type_ref): Declaration removed.
> ? ? ? ?(gimple_fold_call): Declare.
> ? ? ? ?(gimple_adjust_this_by_delta): Likewise.
> ? ? ? ?* cgraph.c (cgraph_make_edge_direct): New parameter delta. ?Updated
> ? ? ? ?all users.
> ? ? ? ?(cgraph_clone_edge): Create a copy of indirect_info also for direct
> ? ? ? ?edges.
> ? ? ? ?* cgraphunit.c (cgraph_redirect_edge_call_stmt_to_callee): Adjust this
> ? ? ? ?parameters.
> ? ? ? ?* gimple-fold.c (gimple_fold_obj_type_ref_known_binfo): Renamed to
> ? ? ? ?gimple_get_virt_mehtod_for_binfo, new parameter delta. ?Do not search
> ? ? ? ?through thunks, in fact bail out if we encounter one, check that
> ? ? ? ?BINFO_VIRTUALS is not NULL.
> ? ? ? ?(gimple_adjust_this_by_delta): New function.
> ? ? ? ?(gimple_fold_obj_type_ref): Removed.
> ? ? ? ?(gimple_fold_obj_type_ref_call): New function.
> ? ? ? ?(fold_gimple_call): Renamed to gimple_fold_call, made external.
> ? ? ? ?Updated users. ?Call gimple_fold_obj_type_ref_call instead of
> ? ? ? ?gimple_fold_obj_type_ref.
> ? ? ? ?* ipa-cp.c (ipcp_process_devirtualization_opportunities): Process
> ? ? ? ?thunk deltas.
> ? ? ? ?(ipcp_discover_new_direct_edges): Likewise.
> ? ? ? ?* ipa-prop.c (ipa_make_edge_direct_to_target): New parameter delta.
> ? ? ? ?Updated callers.
> ? ? ? ?(ipa_write_indirect_edge_info): Stream thunk_delta.
> ? ? ? ?(ipa_read_indirect_edge_info): Likewise.
> ? ? ? ?* tree-ssa-ccp.c (ccp_fold_stmt): Use gimple_fold_call instead of
> ? ? ? ?gimple_fold_obj_type_ref.
>
> ? ? ? ?* testsuite/g++.dg/ipa/pr46053.C: New test.
> ? ? ? ?* testsuite/g++.dg/ipa/pr46287-1.C: Likewise.
> ? ? ? ?* testsuite/g++.dg/ipa/pr46287-2.C: Likewise.
> ? ? ? ?* testsuite/g++.dg/ipa/pr46287-3.C: Likewise.
> ? ? ? ?* testsuite/g++.dg/torture/covariant-1.C: Likewise.
> ? ? ? ?* testsuite/g++.dg/torture/pr46287.C: Likewise.
>
> Index: icln/gcc/cgraph.c
> ===================================================================
> --- icln.orig/gcc/cgraph.c
> +++ icln/gcc/cgraph.c
> @@ -859,7 +859,7 @@ cgraph_set_call_stmt (struct cgraph_edge
> ? ? ? ? indirect call into a direct one. ?*/
> ? ? ? struct cgraph_node *new_callee = cgraph_node (decl);
>
> - ? ? ?cgraph_make_edge_direct (e, new_callee);
> + ? ? ?cgraph_make_edge_direct (e, new_callee, NULL);
> ? ? }
>
> ? push_cfun (DECL_STRUCT_FUNCTION (e->caller->decl));
> @@ -1194,12 +1194,15 @@ cgraph_redirect_edge_callee (struct cgra
> ?}
>
> ?/* Make an indirect EDGE with an unknown callee an ordinary edge leading to
> - ? CALLEE. ?*/
> + ? CALLEE. ?DELTA, if non-NULL, is an integer constant that is to be added to
> + ? the this pointer (first parameter). ?*/
>
> ?void
> -cgraph_make_edge_direct (struct cgraph_edge *edge, struct cgraph_node *callee)
> +cgraph_make_edge_direct (struct cgraph_edge *edge, struct cgraph_node *callee,
> + ? ? ? ? ? ? ? ? ? ? ? ?tree delta)
> ?{
> ? edge->indirect_unknown_callee = 0;
> + ?edge->indirect_info->thunk_delta = delta;
>
> ? /* Get the edge out of the indirect edge list. */
> ? if (edge->prev_callee)
> @@ -2115,8 +2118,16 @@ cgraph_clone_edge (struct cgraph_edge *e
> ? ? ? ?}
> ? ? }
> ? else
> - ? ?new_edge = cgraph_create_edge (n, e->callee, call_stmt, count, freq,
> - ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ?e->loop_nest + loop_nest);
> + ? ?{
> + ? ? ?new_edge = cgraph_create_edge (n, e->callee, call_stmt, count, freq,
> + ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ?e->loop_nest + loop_nest);
> + ? ? ?if (e->indirect_info)
> + ? ? ? {
> + ? ? ? ? new_edge->indirect_info
> + ? ? ? ? ? = ggc_alloc_cleared_cgraph_indirect_call_info ();
> + ? ? ? ? *new_edge->indirect_info = *e->indirect_info;
> + ? ? ? }
> + ? ?}
>
> ? new_edge->inline_failed = e->inline_failed;
> ? new_edge->indirect_inlining_edge = e->indirect_inlining_edge;
> Index: icln/gcc/cgraph.h
> ===================================================================
> --- icln.orig/gcc/cgraph.h
> +++ icln/gcc/cgraph.h
> @@ -399,6 +399,9 @@ struct GTY(()) cgraph_indirect_call_info
> ? HOST_WIDE_INT otr_token;
> ? /* Type of the object from OBJ_TYPE_REF_OBJECT. */
> ? tree otr_type;
> + ?/* Delta by which must be added to this parameter. ?For polymorphic calls
> + ? ? only. ?*/
> + ?tree thunk_delta;
> ? /* Index of the parameter that is called. ?*/
> ? int param_index;
> ? /* ECF flags determined from the caller. ?*/
> @@ -586,7 +589,7 @@ struct cgraph_node * cgraph_clone_node (
> ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ?int, bool, VEC(cgraph_edge_p,heap) *);
>
> ?void cgraph_redirect_edge_callee (struct cgraph_edge *, struct cgraph_node *);
> -void cgraph_make_edge_direct (struct cgraph_edge *, struct cgraph_node *);
> +void cgraph_make_edge_direct (struct cgraph_edge *, struct cgraph_node *, tree);
>
> ?struct cgraph_asm_node *cgraph_add_asm_node (tree);
>
> Index: icln/gcc/cgraphunit.c
> ===================================================================
> --- icln.orig/gcc/cgraphunit.c
> +++ icln/gcc/cgraphunit.c
> @@ -2116,6 +2116,8 @@ cgraph_redirect_edge_call_stmt_to_callee
> ?{
> ? tree decl = gimple_call_fndecl (e->call_stmt);
> ? gimple new_stmt;
> + ?gimple_stmt_iterator gsi;
> + ?bool gsi_computed = false;
> ?#ifdef ENABLE_CHECKING
> ? struct cgraph_node *node;
> ?#endif
> @@ -2148,9 +2150,24 @@ cgraph_redirect_edge_call_stmt_to_callee
> ? ? ? ?}
> ? ? }
>
> + ?if (e->indirect_info && e->indirect_info->thunk_delta
> + ? ? ?&& integer_nonzerop (e->indirect_info->thunk_delta))
> + ? ?{
> + ? ? ?if (cgraph_dump_file)
> + ? ? ? {
> + ? ? ? ? fprintf (cgraph_dump_file, " ? ? ? ? ?Thunk delta is ");
> + ? ? ? ? print_generic_expr (cgraph_dump_file,
> + ? ? ? ? ? ? ? ? ? ? ? ? ? ? e->indirect_info->thunk_delta, 0);
> + ? ? ? ? fprintf (cgraph_dump_file, "\n");
> + ? ? ? }
> + ? ? ?gsi = gsi_for_stmt (e->call_stmt);
> + ? ? ?gsi_computed = true;
> + ? ? ?gimple_adjust_this_by_delta (&gsi, e->indirect_info->thunk_delta);
> + ? ? ?e->indirect_info->thunk_delta = NULL_TREE;
> + ? ?}
> +
> ? if (e->callee->clone.combined_args_to_skip)
> ? ? {
> - ? ? ?gimple_stmt_iterator gsi;
> ? ? ? int lp_nr;
>
> ? ? ? new_stmt
> @@ -2162,7 +2179,8 @@ cgraph_redirect_edge_call_stmt_to_callee
> ? ? ? ? ?&& TREE_CODE (gimple_vdef (new_stmt)) == SSA_NAME)
> ? ? ? ?SSA_NAME_DEF_STMT (gimple_vdef (new_stmt)) = new_stmt;
>
> - ? ? ?gsi = gsi_for_stmt (e->call_stmt);
> + ? ? ?if (!gsi_computed)
> + ? ? ? gsi = gsi_for_stmt (e->call_stmt);
> ? ? ? gsi_replace (&gsi, new_stmt, false);
> ? ? ? /* We need to defer cleaning EH info on the new statement to
> ? ? ? ? ?fixup-cfg. ?We may not have dominator information at this point
> Index: icln/gcc/gimple-fold.c
> ===================================================================
> --- icln.orig/gcc/gimple-fold.c
> +++ icln/gcc/gimple-fold.c
> @@ -1442,17 +1442,26 @@ gimple_get_relevant_ref_binfo (tree ref,
> ? ? }
> ?}
>
> -/* Fold a OBJ_TYPE_REF expression to the address of a function. TOKEN is
> - ? integer form of OBJ_TYPE_REF_TOKEN of the reference expression. ?KNOWN_BINFO
> - ? carries the binfo describing the true type of OBJ_TYPE_REF_OBJECT(REF). ?*/
> +/* Return a declaration of a function which an OBJ_TYPE_REF references. TOKEN
> + ? is integer form of OBJ_TYPE_REF_TOKEN of the reference expression.
> + ? KNOWN_BINFO carries the binfo describing the true type of
> + ? OBJ_TYPE_REF_OBJECT(REF). ?If a call to the function must be accompanied
> + ? with a this adjustment, the constant which should be added to this pointer
> + ? is stored to *DELTA. ?If REFUSE_THUNKS is true, return NULL if the function
> + ? is a thunk (other than a this adjustment which is dealt with by DELTA). */
>
> ?tree
> -gimple_fold_obj_type_ref_known_binfo (HOST_WIDE_INT token, tree known_binfo)
> +gimple_get_virt_mehtod_for_binfo (HOST_WIDE_INT token, tree known_binfo,
> + ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? tree *delta, bool refuse_thunks)
> ?{
> ? HOST_WIDE_INT i;
> - ?tree v, fndecl, delta;
> + ?tree v, fndecl;
> + ?struct cgraph_node *node;
>
> ? v = BINFO_VIRTUALS (known_binfo);
> + ?/* If there is no virtual methods leave the OBJ_TYPE_REF alone. ?*/
> + ?if (!v)
> + ? ?return NULL_TREE;
> ? i = 0;
> ? while (i != token)
> ? ? {
> @@ -1462,62 +1471,91 @@ gimple_fold_obj_type_ref_known_binfo (HO
> ? ? }
>
> ? fndecl = TREE_VALUE (v);
> - ?delta = TREE_PURPOSE (v);
> - ?gcc_assert (host_integerp (delta, 0));
> -
> - ?if (integer_nonzerop (delta))
> - ? ?{
> - ? ? ?struct cgraph_node *node = cgraph_get_node (fndecl);
> - ? ? ?HOST_WIDE_INT off = tree_low_cst (delta, 0);
> -
> - ? ? ?if (!node)
> - ? ? ? ?return NULL;
> - ? ? ?for (node = node->same_body; node; node = node->next)
> - ? ? ? ?if (node->thunk.thunk_p && off == node->thunk.fixed_offset)
> - ? ? ? ? ?break;
> - ? ? ?if (node)
> - ? ? ? ?fndecl = node->decl;
> - ? ? ?else
> - ? ? ? ?return NULL;
> - ? ? }
> + ?node = cgraph_get_node_or_alias (fndecl);
> + ?if (refuse_thunks
> + ? ? ?&& (!node
> + ? ?/* Bail out if it is a thunk declaration. ?Since simple this_adjusting
> + ? ? ? thunks are represented by a constant in TREE_PURPOSE of items in
> + ? ? ? BINFO_VIRTUALS, this is a more complicate type which we cannot handle as
> + ? ? ? yet.
> +
> + ? ? ? FIXME: Remove the following condition once we are able to represent
> + ? ? ? thunk information on call graph edges. ?*/
> + ? ? ? ? || (node->same_body_alias && node->thunk.thunk_p)))
> + ? ?return NULL_TREE;
>
> ? /* When cgraph node is missing and function is not public, we cannot
> ? ? ?devirtualize. ?This can happen in WHOPR when the actual method
> ? ? ?ends up in other partition, because we found devirtualization
> ? ? ?possibility too late. ?*/
> - ?if (!can_refer_decl_in_current_unit_p (fndecl))
> - ? ?return NULL;
> - ?return build_fold_addr_expr (fndecl);
> + ?if (!can_refer_decl_in_current_unit_p (TREE_VALUE (v)))
> + ? ?return NULL_TREE;
> +
> + ?*delta = TREE_PURPOSE (v);
> + ?gcc_checking_assert (host_integerp (*delta, 0));
> + ?return fndecl;
> ?}
>
> +/* Generate code adjusting the first parameter of a call statement determined
> + ? by GSI by DELTA. ?*/
>
> -/* Fold a OBJ_TYPE_REF expression to the address of a function. ?If KNOWN_TYPE
> - ? is not NULL_TREE, it is the true type of the outmost encapsulating object if
> - ? that comes from a pointer SSA_NAME. ?If the true outmost encapsulating type
> - ? can be determined from a declaration OBJ_TYPE_REF_OBJECT(REF), it is used
> - ? regardless of KNOWN_TYPE (which thus can be NULL_TREE). ?*/
> +void
> +gimple_adjust_this_by_delta (gimple_stmt_iterator *gsi, tree delta)
> +{
> + ?gimple call_stmt = gsi_stmt (*gsi);
> + ?tree parm, tmp;
> + ?gimple new_stmt;
> +
> + ?delta = fold_convert (sizetype, delta);
> + ?gcc_assert (gimple_call_num_args (call_stmt) >= 1);
> + ?parm = gimple_call_arg (call_stmt, 0);
> + ?gcc_assert (POINTER_TYPE_P (TREE_TYPE (parm)));
> + ?tmp = create_tmp_var (TREE_TYPE (parm), NULL);
> + ?add_referenced_var (tmp);
> +
> + ?tmp = make_ssa_name (tmp, NULL);
> + ?new_stmt = gimple_build_assign_with_ops (POINTER_PLUS_EXPR, tmp, parm, delta);
> + ?SSA_NAME_DEF_STMT (tmp) = new_stmt;
> + ?gsi_insert_before (gsi, new_stmt, GSI_SAME_STMT);
> + ?gimple_call_set_arg (call_stmt, 0, tmp);
> +}
>
> -tree
> -gimple_fold_obj_type_ref (tree ref, tree known_type)
> +/* Fold a call statement to OBJ_TYPE_REF to a direct call, if possible. ?GSI
> + ? determines the statement, generating new statements is allowed only if
> + ? INPLACE is false. ?Return true iff the statement was changed. ?*/
> +
> +static bool
> +gimple_fold_obj_type_ref_call (gimple_stmt_iterator *gsi, bool inplace)
> ?{
> + ?gimple stmt = gsi_stmt (*gsi);
> + ?tree ref = gimple_call_fn (stmt);
> ? tree obj = OBJ_TYPE_REF_OBJECT (ref);
> - ?tree known_binfo = known_type ? TYPE_BINFO (known_type) : NULL_TREE;
> - ?tree binfo;
> + ?tree binfo, fndecl, delta;
> + ?HOST_WIDE_INT token;
>
> ? if (TREE_CODE (obj) == ADDR_EXPR)
> ? ? obj = TREE_OPERAND (obj, 0);
> + ?else
> + ? ?return false;
> +
> + ?binfo = gimple_get_relevant_ref_binfo (obj, NULL_TREE);
> + ?if (!binfo)
> + ? ?return false;
> + ?token = tree_low_cst (OBJ_TYPE_REF_TOKEN (ref), 1);
> + ?fndecl = gimple_get_virt_mehtod_for_binfo (token, binfo, &delta,
> + ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ?!DECL_P (obj));
> + ?if (!fndecl)
> + ? ?return false;
>
> - ?binfo = gimple_get_relevant_ref_binfo (obj, known_binfo);
> - ?if (binfo)
> + ?if (integer_nonzerop (delta))
> ? ? {
> - ? ? ?HOST_WIDE_INT token = tree_low_cst (OBJ_TYPE_REF_TOKEN (ref), 1);
> - ? ? ?/* If there is no virtual methods leave the OBJ_TYPE_REF alone. ?*/
> - ? ? ?if (!BINFO_VIRTUALS (binfo))
> - ? ? ? return NULL_TREE;
> - ? ? ?return gimple_fold_obj_type_ref_known_binfo (token, binfo);
> + ? ? ?if (inplace)
> + ? ? ? ?return false;
> + ? ? ?gimple_adjust_this_by_delta (gsi, delta);
> ? ? }
> - ?else
> - ? ?return NULL_TREE;
> +
> + ?gimple_call_set_fndecl (stmt, fndecl);
> + ?return true;
> ?}
>
> ?/* Attempt to fold a call statement referenced by the statement iterator GSI.
> @@ -1525,8 +1563,8 @@ gimple_fold_obj_type_ref (tree ref, tree
> ? ?simplifies to a constant value. Return true if any changes were made.
> ? ?It is assumed that the operands have been previously folded. ?*/
>
> -static bool
> -fold_gimple_call (gimple_stmt_iterator *gsi, bool inplace)
> +bool
> +gimple_fold_call (gimple_stmt_iterator *gsi, bool inplace)
> ?{
> ? gimple stmt = gsi_stmt (*gsi);
>
> @@ -1552,18 +1590,8 @@ fold_gimple_call (gimple_stmt_iterator *
> ? ? ? ? ?copying EH region info to the new node. ?Easier to just do it
> ? ? ? ? ?here where we can just smash the call operand. ?*/
> ? ? ? callee = gimple_call_fn (stmt);
> - ? ? ?if (TREE_CODE (callee) == OBJ_TYPE_REF
> - ? ? ? ? ?&& TREE_CODE (OBJ_TYPE_REF_OBJECT (callee)) == ADDR_EXPR)
> - ? ? ? ?{
> - ? ? ? ? ?tree t;
> -
> - ? ? ? ? ?t = gimple_fold_obj_type_ref (callee, NULL_TREE);
> - ? ? ? ? ?if (t)
> - ? ? ? ? ? ?{
> - ? ? ? ? ? ? ?gimple_call_set_fn (stmt, t);
> - ? ? ? ? ? ? ?return true;
> - ? ? ? ? ? ?}
> - ? ? ? ?}
> + ? ? ?if (TREE_CODE (callee) == OBJ_TYPE_REF)
> + ? ? ? return gimple_fold_obj_type_ref_call (gsi, inplace);
> ? ? }
>
> ? return false;
> @@ -1617,7 +1645,7 @@ fold_stmt_1 (gimple_stmt_iterator *gsi,
> ? ? ? ? ? ? ? ?changed = true;
> ? ? ? ? ? ? ?}
> ? ? ? ? ?}
> - ? ? ?changed |= fold_gimple_call (gsi, inplace);
> + ? ? ?changed |= gimple_fold_call (gsi, inplace);
> ? ? ? break;
>
> ? ? case GIMPLE_ASM:
> Index: icln/gcc/gimple.h
> ===================================================================
> --- icln.orig/gcc/gimple.h
> +++ icln/gcc/gimple.h
> @@ -894,10 +894,10 @@ unsigned get_gimple_rhs_num_ops (enum tr
> ?#define gimple_alloc(c, n) gimple_alloc_stat (c, n MEM_STAT_INFO)
> ?gimple gimple_alloc_stat (enum gimple_code, unsigned MEM_STAT_DECL);
> ?const char *gimple_decl_printable_name (tree, int);
> -tree gimple_fold_obj_type_ref (tree, tree);
> +bool gimple_fold_call (gimple_stmt_iterator *gsi, bool inplace);
> ?tree gimple_get_relevant_ref_binfo (tree ref, tree known_binfo);
> -tree gimple_fold_obj_type_ref_known_binfo (HOST_WIDE_INT, tree);
> -
> +tree gimple_get_virt_mehtod_for_binfo (HOST_WIDE_INT, tree, tree *, bool);
> +void gimple_adjust_this_by_delta (gimple_stmt_iterator *, tree);
> ?/* Returns true iff T is a valid GIMPLE statement. ?*/
> ?extern bool is_gimple_stmt (tree);
>
> Index: icln/gcc/ipa-cp.c
> ===================================================================
> --- icln.orig/gcc/ipa-cp.c
> +++ icln/gcc/ipa-cp.c
> @@ -1214,7 +1214,7 @@ ipcp_process_devirtualization_opportunit
> ? ? {
> ? ? ? int param_index, types_count, j;
> ? ? ? HOST_WIDE_INT token;
> - ? ? ?tree target;
> + ? ? ?tree target, delta;
>
> ? ? ? next_ie = ie->next_callee;
> ? ? ? if (!ie->indirect_info->polymorphic)
> @@ -1231,7 +1231,8 @@ ipcp_process_devirtualization_opportunit
> ? ? ? for (j = 0; j < types_count; j++)
> ? ? ? ?{
> ? ? ? ? ?tree binfo = VEC_index (tree, info->params[param_index].types, j);
> - ? ? ? ? tree t = gimple_fold_obj_type_ref_known_binfo (token, binfo);
> + ? ? ? ? tree d;
> + ? ? ? ? tree t = gimple_get_virt_mehtod_for_binfo (token, binfo, &d, true);
>
> ? ? ? ? ?if (!t)
> ? ? ? ? ? ?{
> @@ -1239,8 +1240,11 @@ ipcp_process_devirtualization_opportunit
> ? ? ? ? ? ? ?break;
> ? ? ? ? ? ?}
> ? ? ? ? ?else if (!target)
> - ? ? ? ? ? target = t;
> - ? ? ? ? else if (target != t)
> + ? ? ? ? ? {
> + ? ? ? ? ? ? target = t;
> + ? ? ? ? ? ? delta = d;
> + ? ? ? ? ? }
> + ? ? ? ? else if (target != t || !tree_int_cst_equal (delta, d))
> ? ? ? ? ? ?{
> ? ? ? ? ? ? ?target = NULL_TREE;
> ? ? ? ? ? ? ?break;
> @@ -1248,7 +1252,7 @@ ipcp_process_devirtualization_opportunit
> ? ? ? ?}
>
> ? ? ? if (target)
> - ? ? ? ipa_make_edge_direct_to_target (ie, target);
> + ? ? ? ipa_make_edge_direct_to_target (ie, target, delta);
> ? ? }
> ?}
>
> @@ -1288,6 +1292,7 @@ ipcp_discover_new_direct_edges (struct c
> ? for (ie = node->indirect_calls; ie; ie = next_ie)
> ? ? {
> ? ? ? struct cgraph_indirect_call_info *ici = ie->indirect_info;
> + ? ? ?tree target, delta = NULL_TREE;
>
> ? ? ? next_ie = ie->next_callee;
> ? ? ? if (ici->param_index != index)
> @@ -1307,12 +1312,15 @@ ipcp_discover_new_direct_edges (struct c
> ? ? ? ? ? ?continue;
> ? ? ? ? ?gcc_assert (ie->indirect_info->anc_offset == 0);
> ? ? ? ? ?token = ie->indirect_info->otr_token;
> - ? ? ? ? cst = gimple_fold_obj_type_ref_known_binfo (token, binfo);
> - ? ? ? ? if (!cst)
> + ? ? ? ? target = gimple_get_virt_mehtod_for_binfo (token, binfo, &delta,
> + ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ?true);
> + ? ? ? ? if (!target)
> ? ? ? ? ? ?continue;
> ? ? ? ?}
> + ? ? ?else
> + ? ? ? target = cst;
>
> - ? ? ?ipa_make_edge_direct_to_target (ie, cst);
> + ? ? ?ipa_make_edge_direct_to_target (ie, target, delta);
> ? ? }
> ?}
>
> Index: icln/gcc/ipa-prop.c
> ===================================================================
> --- icln.orig/gcc/ipa-prop.c
> +++ icln/gcc/ipa-prop.c
> @@ -1458,35 +1458,43 @@ update_jump_functions_after_inlining (st
> ?}
>
> ?/* If TARGET is an addr_expr of a function declaration, make it the destination
> - ? of an indirect edge IE and return the edge. ?Otherwise, return NULL. ?*/
> + ? of an indirect edge IE and return the edge. ?Otherwise, return NULL. ?Delta,
> + ? if non-NULL, is an integer constant that must be added to this pointer
> + ? (first parameter). ?*/
>
> ?struct cgraph_edge *
> -ipa_make_edge_direct_to_target (struct cgraph_edge *ie, tree target)
> +ipa_make_edge_direct_to_target (struct cgraph_edge *ie, tree target, tree delta)
> ?{
> ? struct cgraph_node *callee;
>
> - ?if (TREE_CODE (target) != ADDR_EXPR)
> - ? ?return NULL;
> - ?target = TREE_OPERAND (target, 0);
> + ?if (TREE_CODE (target) == ADDR_EXPR)
> + ? ?target = TREE_OPERAND (target, 0);
> ? if (TREE_CODE (target) != FUNCTION_DECL)
> ? ? return NULL;
> ? callee = cgraph_node (target);
> ? if (!callee)
> ? ? return NULL;
> ? ipa_check_create_node_params ();
> - ?cgraph_make_edge_direct (ie, callee);
> +
> + ?cgraph_make_edge_direct (ie, callee, delta);
> ? if (dump_file)
> ? ? {
> ? ? ? fprintf (dump_file, "ipa-prop: Discovered %s call to a known target "
> - ? ? ? ? ? ? ?"(%s/%i -> %s/%i) for stmt ",
> + ? ? ? ? ? ? ?"(%s/%i -> %s/%i), for stmt ",
> ? ? ? ? ? ? ? ie->indirect_info->polymorphic ? "a virtual" : "an indirect",
> ? ? ? ? ? ? ? cgraph_node_name (ie->caller), ie->caller->uid,
> ? ? ? ? ? ? ? cgraph_node_name (ie->callee), ie->callee->uid);
> -
> ? ? ? if (ie->call_stmt)
> ? ? ? ?print_gimple_stmt (dump_file, ie->call_stmt, 2, TDF_SLIM);
> ? ? ? else
> ? ? ? ?fprintf (dump_file, "with uid %i\n", ie->lto_stmt_uid);
> +
> + ? ? ?if (delta)
> + ? ? ? {
> + ? ? ? ? fprintf (dump_file, " ? ? ? ? ?Thunk delta is ");
> + ? ? ? ? print_generic_expr (dump_file, delta, 0);
> + ? ? ? ? fprintf (dump_file, "\n");
> + ? ? ? }
> ? ? }
>
> ? if (ipa_get_cs_argument_count (IPA_EDGE_REF (ie))
> @@ -1514,7 +1522,7 @@ try_make_edge_direct_simple_call (struct
> ? else
> ? ? return NULL;
>
> - ?return ipa_make_edge_direct_to_target (ie, target);
> + ?return ipa_make_edge_direct_to_target (ie, target, NULL_TREE);
> ?}
>
> ?/* Try to find a destination for indirect edge IE that corresponds to a
> @@ -1526,7 +1534,7 @@ static struct cgraph_edge *
> ?try_make_edge_direct_virtual_call (struct cgraph_edge *ie,
> ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? struct ipa_jump_func *jfunc)
> ?{
> - ?tree binfo, type, target;
> + ?tree binfo, type, target, delta;
> ? HOST_WIDE_INT token;
>
> ? if (jfunc->type == IPA_JF_KNOWN_TYPE)
> @@ -1550,12 +1558,12 @@ try_make_edge_direct_virtual_call (struc
> ? type = ie->indirect_info->otr_type;
> ? binfo = get_binfo_at_offset (binfo, ie->indirect_info->anc_offset, type);
> ? if (binfo)
> - ? ?target = gimple_fold_obj_type_ref_known_binfo (token, binfo);
> + ? ?target = gimple_get_virt_mehtod_for_binfo (token, binfo, &delta, true);
> ? else
> ? ? return NULL;
>
> ? if (target)
> - ? ?return ipa_make_edge_direct_to_target (ie, target);
> + ? ?return ipa_make_edge_direct_to_target (ie, target, delta);
> ? else
> ? ? return NULL;
> ?}
> @@ -2546,6 +2554,7 @@ ipa_write_indirect_edge_info (struct out
> ? ? {
> ? ? ? lto_output_sleb128_stream (ob->main_stream, ii->otr_token);
> ? ? ? lto_output_tree (ob, ii->otr_type, true);
> + ? ? ?lto_output_tree (ob, ii->thunk_delta, true);
> ? ? }
> ?}
>
> @@ -2568,6 +2577,7 @@ ipa_read_indirect_edge_info (struct lto_
> ? ? {
> ? ? ? ii->otr_token = (HOST_WIDE_INT) lto_input_sleb128 (ib);
> ? ? ? ii->otr_type = lto_input_tree (ib, data_in);
> + ? ? ?ii->thunk_delta = lto_input_tree (ib, data_in);
> ? ? }
> ?}
>
> Index: icln/gcc/ipa-prop.h
> ===================================================================
> --- icln.orig/gcc/ipa-prop.h
> +++ icln/gcc/ipa-prop.h
> @@ -430,7 +430,8 @@ bool ipa_propagate_indirect_call_infos (
> ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ?VEC (cgraph_edge_p, heap) **new_edges);
>
> ?/* Indirect edge and binfo processing. ?*/
> -struct cgraph_edge *ipa_make_edge_direct_to_target (struct cgraph_edge *, tree);
> +struct cgraph_edge *ipa_make_edge_direct_to_target (struct cgraph_edge *, tree,
> + ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? tree);
>
>
> ?/* Debugging interface. ?*/
> Index: icln/gcc/tree-ssa-ccp.c
> ===================================================================
> --- icln.orig/gcc/tree-ssa-ccp.c
> +++ icln/gcc/tree-ssa-ccp.c
> @@ -2321,16 +2321,8 @@ ccp_fold_stmt (gimple_stmt_iterator *gsi
> ? ? ? ? ?{
> ? ? ? ? ? ?tree expr = OBJ_TYPE_REF_EXPR (callee);
> ? ? ? ? ? ?OBJ_TYPE_REF_EXPR (callee) = valueize_op (expr);
> - ? ? ? ? ? if (TREE_CODE (OBJ_TYPE_REF_EXPR (callee)) == ADDR_EXPR)
> - ? ? ? ? ? ? {
> - ? ? ? ? ? ? ? tree t;
> - ? ? ? ? ? ? ? t = gimple_fold_obj_type_ref (callee, NULL_TREE);
> - ? ? ? ? ? ? ? if (t)
> - ? ? ? ? ? ? ? ? {
> - ? ? ? ? ? ? ? ? ? gimple_call_set_fn (stmt, t);
> - ? ? ? ? ? ? ? ? ? changed = true;
> - ? ? ? ? ? ? ? ? }
> - ? ? ? ? ? ? }
> + ? ? ? ? ? if (gimple_fold_call (gsi, false))
> + ? ? ? ? ? ? changed = true;
> ? ? ? ? ? ?OBJ_TYPE_REF_EXPR (callee) = expr;
> ? ? ? ? ?}
>
> Index: icln/gcc/testsuite/g++.dg/ipa/pr46053.C
> ===================================================================
> --- /dev/null
> +++ icln/gcc/testsuite/g++.dg/ipa/pr46053.C
> @@ -0,0 +1,41 @@
> +/* { dg-do run } */
> +/* { dg-options "-O -fipa-cp -fno-early-inlining" ?} */
> +
> +extern "C" void abort ();
> +
> +struct A
> +{
> + ?virtual void foo () = 0;
> +};
> +
> +struct B : A
> +{
> + ?virtual void foo () = 0;
> +};
> +
> +struct C : A
> +{
> +};
> +
> +struct D : C, B
> +{
> + ?int i;
> + ?D () : i(0xaaaa) {}
> + ?virtual void foo ()
> + ?{
> + ? ?if (i != 0xaaaa)
> + ? ? ?abort();
> + ?}
> +};
> +
> +static inline void bar (B &b)
> +{
> + ?b.foo ();
> +}
> +
> +int main()
> +{
> + ?D d;
> + ?bar (d);
> + ?return 0;
> +}
> Index: icln/gcc/testsuite/g++.dg/ipa/pr46287-1.C
> ===================================================================
> --- /dev/null
> +++ icln/gcc/testsuite/g++.dg/ipa/pr46287-1.C
> @@ -0,0 +1,67 @@
> +// Check that indirect calls to thunks do not lead to errors.
> +// { dg-do run }
> +// { dg-options "-O" }
> +
> +extern "C" void abort ();
> +
> +class A
> +{
> +public:
> + ?virtual void foo () {abort();}
> +};
> +
> +class B : public A
> +{
> +public:
> + ?int z;
> + ?virtual void foo () {abort();}
> +};
> +
> +class C : public A
> +{
> +public:
> + ?void *a[32];
> + ?unsigned long b;
> + ?long c[32];
> +
> + ?virtual void foo () {abort();}
> +};
> +
> +class D : public C, public B
> +{
> +public:
> + ?D () : C(), B()
> + ?{
> + ? ?int i;
> + ? ?for (i = 0; i < 32; i++)
> + ? ? ?{
> + ? ? ? a[i] = (void *) 0;
> + ? ? ? c[i] = 0;
> + ? ? ?}
> + ? ?b = 0xaaaa;
> + ?}
> +
> + ?virtual void foo ();
> +};
> +
> +inline void D::foo()
> +{
> + ?if (b != 0xaaaa)
> + ? ?abort();
> +}
> +
> +static inline void bar (B &b)
> +{
> +
> + ?b.foo ();
> +}
> +
> +int main()
> +{
> + ?int i;
> + ?D d;
> +
> + ?for (i = 0; i < 5000; i++)
> + ? ?bar (d);
> + ?return 0;
> +}
> Index: icln/gcc/testsuite/g++.dg/ipa/pr46287-2.C
> ===================================================================
> --- /dev/null
> +++ icln/gcc/testsuite/g++.dg/ipa/pr46287-2.C
> @@ -0,0 +1,68 @@
> +// Check that indirect calls to thunks do not lead to errors.
> +// { dg-do run }
> +// { dg-options "-O -finline -finline-small-functions -finline-functions" }
> +
> +
> +extern "C" void abort ();
> +
> +class A
> +{
> +public:
> + ?virtual void foo () {abort();}
> +};
> +
> +class B : public A
> +{
> +public:
> + ?int z;
> + ?virtual void foo () {abort();}
> +};
> +
> +class C : public A
> +{
> +public:
> + ?void *a[32];
> + ?unsigned long b;
> + ?long c[32];
> +
> + ?virtual void foo () {abort();}
> +};
> +
> +class D : public C, public B
> +{
> +public:
> + ?D () : C(), B()
> + ?{
> + ? ?int i;
> + ? ?for (i = 0; i < 32; i++)
> + ? ? ?{
> + ? ? ? a[i] = (void *) 0;
> + ? ? ? c[i] = 0;
> + ? ? ?}
> + ? ?b = 0xaaaa;
> + ?}
> +
> + ?virtual void foo ();
> +};
> +
> +void D::foo()
> +{
> + ?if (b != 0xaaaa)
> + ? ?abort();
> +}
> +
> +static inline void bar (B &b)
> +{
> +
> + ?b.foo ();
> +}
> +
> +int main()
> +{
> + ?int i;
> + ?D d;
> +
> + ?for (i = 0; i < 5000; i++)
> + ? ?bar (d);
> + ?return 0;
> +}
> Index: icln/gcc/testsuite/g++.dg/ipa/pr46287-3.C
> ===================================================================
> --- /dev/null
> +++ icln/gcc/testsuite/g++.dg/ipa/pr46287-3.C
> @@ -0,0 +1,67 @@
> +// Check that indirect calls to thunks do not lead to errors.
> +// { dg-do run }
> +// { dg-options "-O -fipa-cp" }
> +
> +extern "C" void abort ();
> +
> +class A
> +{
> +public:
> + ?virtual void foo () {abort();}
> +};
> +
> +class B : public A
> +{
> +public:
> + ?int z;
> + ?virtual void foo () {abort();}
> +};
> +
> +class C : public A
> +{
> +public:
> + ?void *a[32];
> + ?unsigned long b;
> + ?long c[32];
> +
> + ?virtual void foo () {abort();}
> +};
> +
> +class D : public C, public B
> +{
> +public:
> + ?D () : C(), B()
> + ?{
> + ? ?int i;
> + ? ?for (i = 0; i < 32; i++)
> + ? ? ?{
> + ? ? ? a[i] = (void *) 0;
> + ? ? ? c[i] = 0;
> + ? ? ?}
> + ? ?b = 0xaaaa;
> + ?}
> +
> + ?virtual void foo ();
> +};
> +
> +void D::foo()
> +{
> + ?if (b != 0xaaaa)
> + ? ?abort();
> +}
> +
> +static void bar (B &b)
> +{
> +
> + ?b.foo ();
> +}
> +
> +int main()
> +{
> + ?int i;
> + ?D d;
> +
> + ?for (i = 0; i < 5000; i++)
> + ? ?bar (d);
> + ?return 0;
> +}
> Index: icln/gcc/testsuite/g++.dg/torture/covariant-1.C
> ===================================================================
> --- /dev/null
> +++ icln/gcc/testsuite/g++.dg/torture/covariant-1.C
> @@ -0,0 +1,33 @@
> +// { dg-do run }
> +
> +extern "C" void abort ();
> +
> +class A {
> +public:
> + ?virtual A* getThis() { return this; }
> +};
> +
> +class B {
> +int a;
> +public:
> + ?virtual B* getThis() { return this; }
> +};
> +
> +class AB : public A, public B {
> +public:
> + ?virtual AB* getThis() { return this; }
> +};
> +
> +int main ()
> +{
> + ?AB ab;
> +
> + ?A* a = &ab;
> + ?B* b = &ab;
> +
> + ?if (a->getThis() != a
> + ? ? ?|| b->getThis() != b)
> + ? ?abort ();
> +
> + ?return 0;
> +}
> Index: icln/gcc/testsuite/g++.dg/torture/pr46287.C
> ===================================================================
> --- /dev/null
> +++ icln/gcc/testsuite/g++.dg/torture/pr46287.C
> @@ -0,0 +1,66 @@
> +// Check that indirect calls to thunks do not lead to errors.
> +// { dg-do run }
> +
> +extern "C" void abort ();
> +
> +class A
> +{
> +public:
> + ?virtual void foo () {abort();}
> +};
> +
> +class B : public A
> +{
> +public:
> + ?int z;
> + ?virtual void foo () {abort();}
> +};
> +
> +class C : public A
> +{
> +public:
> + ?void *a[32];
> + ?unsigned long b;
> + ?long c[32];
> +
> + ?virtual void foo () {abort();}
> +};
> +
> +class D : public C, public B
> +{
> +public:
> + ?D () : C(), B()
> + ?{
> + ? ?int i;
> + ? ?for (i = 0; i < 32; i++)
> + ? ? ?{
> + ? ? ? a[i] = (void *) 0;
> + ? ? ? c[i] = 0;
> + ? ? ?}
> + ? ?b = 0xaaaa;
> + ?}
> +
> + ?virtual void foo ();
> +};
> +
> +void D::foo()
> +{
> + ?if (b != 0xaaaa)
> + ? ?abort();
> +}
> +
> +static inline void bar (B &b)
> +{
> +
> + ?b.foo ();
> +}
> +
> +int main()
> +{
> + ?int i;
> + ?D d;
> +
> + ?for (i = 0; i < 5000; i++)
> + ? ?bar (d);
> + ?return 0;
> +}
>
>
>


Index Nav: [Date Index] [Subject Index] [Author Index] [Thread Index]
Message Nav: [Date Prev] [Date Next] [Thread Prev] [Thread Next]