[PATCH PING, PR 46287] Do not generate direct calls to thunks
Richard Guenther
richard.guenther@gmail.com
Tue Nov 23 13:04:00 GMT 2010
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;
> +}
>
>
>
More information about the Gcc-patches
mailing list