===================================================================
@@ -338,9 +338,11 @@ typedef enum cgraph_inline_failed_enum {
struct GTY(()) cgraph_indirect_call_info
{
- /* Offset accumulated from ancestor jump functions of inlined call graph
- edges. */
- HOST_WIDE_INT anc_offset;
+ /* When polymorphic is set, this field contains offset where the object which
+ was actually used in the polymorphic resides within a larger structure.
+ If agg_contents is set, the field contains the offset within the aggregate
+ from which the address to call was loaded. */
+ HOST_WIDE_INT offset;
/* OBJ_TYPE_REF_TOKEN of a polymorphic call (if polymorphic is set). */
HOST_WIDE_INT otr_token;
/* Type of the object from OBJ_TYPE_REF_OBJECT. */
@@ -353,6 +355,9 @@ struct GTY(()) cgraph_indirect_call_info
/* Set when the call is a virtual call with the parameter being the
associated object pointer rather than a simple direct call. */
unsigned polymorphic : 1;
+ /* Set when the call is a call of a pointer loaded from contents of an
+ aggregate at offset. */
+ unsigned agg_contents : 1;
};
struct GTY((chain_next ("%h.next_caller"), chain_prev ("%h.prev_caller"))) cgraph_edge {
===================================================================
@@ -182,14 +182,6 @@ ipa_print_node_jump_functions_for_edge (
}
fprintf (f, "\n");
}
- else if (type == IPA_JF_CONST_MEMBER_PTR)
- {
- fprintf (f, "CONST MEMBER PTR: ");
- print_generic_expr (f, jump_func->value.member_cst.pfn, 0);
- fprintf (f, ", ");
- print_generic_expr (f, jump_func->value.member_cst.delta, 0);
- fprintf (f, "\n");
- }
else if (type == IPA_JF_PASS_THROUGH)
{
fprintf (f, "PASS THROUGH: ");
@@ -356,18 +348,6 @@ ipa_set_ancestor_jf (struct ipa_jump_fun
jfunc->value.ancestor.agg_preserved = agg_preserved;
}
-/* Simple function filling in a member pointer constant jump function (with PFN
- and DELTA as the constant value) into JFUNC. */
-
-static void
-ipa_set_jf_member_ptr_cst (struct ipa_jump_func *jfunc,
- tree pfn, tree delta)
-{
- jfunc->type = IPA_JF_CONST_MEMBER_PTR;
- jfunc->value.member_cst.pfn = pfn;
- jfunc->value.member_cst.delta = delta;
-}
-
/* Structure to be passed in between detect_type_change and
check_stmt_for_type_change. */
@@ -1013,14 +993,16 @@ type_like_member_ptr_p (tree type, tree
fld = TYPE_FIELDS (type);
if (!fld || !POINTER_TYPE_P (TREE_TYPE (fld))
- || TREE_CODE (TREE_TYPE (TREE_TYPE (fld))) != METHOD_TYPE)
+ || TREE_CODE (TREE_TYPE (TREE_TYPE (fld))) != METHOD_TYPE
+ || !host_integerp (DECL_FIELD_OFFSET (fld), 1))
return false;
if (method_ptr)
*method_ptr = fld;
fld = DECL_CHAIN (fld);
- if (!fld || INTEGRAL_TYPE_P (fld))
+ if (!fld || INTEGRAL_TYPE_P (fld)
+ || !host_integerp (DECL_FIELD_OFFSET (fld), 1))
return false;
if (delta)
*delta = fld;
@@ -1050,83 +1032,6 @@ get_ssa_def_if_simple_copy (tree rhs)
return rhs;
}
-/* Traverse statements from CALL backwards, scanning whether the argument ARG
- which is a member pointer is filled in with constant values. If it is, fill
- the jump function JFUNC in appropriately. METHOD_FIELD and DELTA_FIELD are
- fields of the record type of the member pointer. To give an example, we
- look for a pattern looking like the following:
-
- D.2515.__pfn ={v} printStuff;
- D.2515.__delta ={v} 0;
- i_1 = doprinting (D.2515); */
-
-static void
-determine_cst_member_ptr (gimple call, tree arg, tree method_field,
- tree delta_field, struct ipa_jump_func *jfunc)
-{
- gimple_stmt_iterator gsi;
- tree method = NULL_TREE;
- tree delta = NULL_TREE;
-
- gsi = gsi_for_stmt (call);
-
- gsi_prev (&gsi);
- for (; !gsi_end_p (gsi); gsi_prev (&gsi))
- {
- gimple stmt = gsi_stmt (gsi);
- tree lhs, rhs, fld;
-
- if (!stmt_may_clobber_ref_p (stmt, arg))
- continue;
- if (!gimple_assign_single_p (stmt))
- return;
-
- lhs = gimple_assign_lhs (stmt);
- rhs = gimple_assign_rhs1 (stmt);
-
- if (TREE_CODE (lhs) != COMPONENT_REF
- || TREE_OPERAND (lhs, 0) != arg)
- return;
-
- fld = TREE_OPERAND (lhs, 1);
- if (!method && fld == method_field)
- {
- rhs = get_ssa_def_if_simple_copy (rhs);
- if (TREE_CODE (rhs) == ADDR_EXPR
- && TREE_CODE (TREE_OPERAND (rhs, 0)) == FUNCTION_DECL
- && TREE_CODE (TREE_TYPE (TREE_OPERAND (rhs, 0))) == METHOD_TYPE)
- {
- method = TREE_OPERAND (rhs, 0);
- if (delta)
- {
- ipa_set_jf_member_ptr_cst (jfunc, rhs, delta);
- return;
- }
- }
- else
- return;
- }
-
- if (!delta && fld == delta_field)
- {
- rhs = get_ssa_def_if_simple_copy (rhs);
- if (TREE_CODE (rhs) == INTEGER_CST)
- {
- delta = rhs;
- if (method)
- {
- ipa_set_jf_member_ptr_cst (jfunc, rhs, delta);
- return;
- }
- }
- else
- return;
- }
- }
-
- return;
-}
-
/* Helper for determine_known_aggregate_parts, initializes *R for an aggregate
passed by reference based on BASE and with the given TYPE. */
@@ -1383,32 +1288,20 @@ ipa_compute_jump_functions_for_edge (str
if (is_gimple_ip_invariant (arg))
ipa_set_jf_constant (jfunc, arg);
- else if (!is_gimple_reg_type (TREE_TYPE (arg)))
+ else if (!is_gimple_reg_type (TREE_TYPE (arg))
+ && TREE_CODE (arg) == PARM_DECL)
{
- tree method_field, delta_field;
-
- /* Aggregate passed by value, check for pass-through, otherwise fill
- in aggregate contents. */
+ int index = ipa_get_param_decl_index (info, arg);
- if (TREE_CODE (arg) == PARM_DECL)
+ gcc_assert (index >=0);
+ /* Aggregate passed by value, check for pass-through, otherwise we
+ will attempt to fill in aggregate contents later in this
+ function. */
+ if (is_parm_preserved_before_stmt (&parms_ainfo[index], call, arg))
{
- int index = ipa_get_param_decl_index (info, arg);
- gcc_assert (index >=0);
- if (is_parm_preserved_before_stmt (&parms_ainfo[index], call,
- arg))
- {
- ipa_set_jf_simple_pass_through (jfunc, index, true);
- continue;
- }
+ ipa_set_jf_simple_pass_through (jfunc, index, true);
+ continue;
}
-
- /* TODO: The call to determine_cst_member_ptr will be removed by a
- subsequent patch which will do away with IPA_JF_CONST_MEMBER_PTR
- altogether. */
- if (type_like_member_ptr_p (TREE_TYPE (arg), &method_field,
- &delta_field))
- determine_cst_member_ptr (call, arg, method_field, delta_field,
- jfunc);
}
else if (TREE_CODE (arg) == SSA_NAME)
{
@@ -1442,7 +1335,6 @@ ipa_compute_jump_functions_for_edge (str
|| !ipa_get_jf_pass_through_agg_preserved (jfunc))
&& (jfunc->type != IPA_JF_ANCESTOR
|| !ipa_get_jf_ancestor_agg_preserved (jfunc))
- && jfunc->type != IPA_JF_CONST_MEMBER_PTR
&& (AGGREGATE_TYPE_P (TREE_TYPE (arg))
|| (POINTER_TYPE_P (TREE_TYPE (arg))
&& AGGREGATE_TYPE_P (TREE_TYPE (TREE_TYPE (arg))))))
@@ -1474,16 +1366,22 @@ ipa_compute_jump_functions (struct cgrap
ipa_compute_jump_functions_for_edge (parms_ainfo, cs);
}
-/* If RHS looks like a rhs of a statement loading pfn from a member
- pointer formal parameter, return the parameter, otherwise return
- NULL. If USE_DELTA, then we look for a use of the delta field
- rather than the pfn. */
+/* If STMT looks like a statement loading a value from a member pointer formal
+ parameter, return that parameter and store the offset of the field to
+ *OFFSET_P, if it is non-NULL. Otherwise return NULL (but *OFFSET_P still
+ might be clobbered). If USE_DELTA, then we look for a use of the delta
+ field rather than the pfn. */
static tree
-ipa_get_member_ptr_load_param (tree rhs, bool use_delta)
+ipa_get_stmt_member_ptr_load_param (gimple stmt, bool use_delta,
+ HOST_WIDE_INT *offset_p)
{
- tree rec, ref_field, ref_offset, fld, fld_offset, ptr_field, delta_field;
+ tree rhs, rec, ref_field, ref_offset, fld, ptr_field, delta_field;
+
+ if (!gimple_assign_single_p (stmt))
+ return NULL_TREE;
+ rhs = gimple_assign_rhs1 (stmt);
if (TREE_CODE (rhs) == COMPONENT_REF)
{
ref_field = TREE_OPERAND (rhs, 1);
@@ -1500,43 +1398,24 @@ ipa_get_member_ptr_load_param (tree rhs,
if (TREE_CODE (rec) != PARM_DECL
|| !type_like_member_ptr_p (TREE_TYPE (rec), &ptr_field, &delta_field))
return NULL_TREE;
-
ref_offset = TREE_OPERAND (rhs, 1);
+ if (use_delta)
+ fld = delta_field;
+ else
+ fld = ptr_field;
+ if (offset_p)
+ *offset_p = int_bit_position (fld);
+
if (ref_field)
{
if (integer_nonzerop (ref_offset))
return NULL_TREE;
-
- if (use_delta)
- fld = delta_field;
- else
- fld = ptr_field;
-
return ref_field == fld ? rec : NULL_TREE;
}
-
- if (use_delta)
- fld_offset = byte_position (delta_field);
else
- fld_offset = byte_position (ptr_field);
-
- return tree_int_cst_equal (ref_offset, fld_offset) ? rec : NULL_TREE;
-}
-
-/* If STMT looks like a statement loading a value from a member pointer formal
- parameter, this function returns that parameter. */
-
-static tree
-ipa_get_stmt_member_ptr_load_param (gimple stmt, bool use_delta)
-{
- tree rhs;
-
- if (!gimple_assign_single_p (stmt))
- return NULL_TREE;
-
- rhs = gimple_assign_rhs1 (stmt);
- return ipa_get_member_ptr_load_param (rhs, use_delta);
+ return tree_int_cst_equal (byte_position (fld), ref_offset) ? rec
+ : NULL_TREE;
}
/* Returns true iff T is an SSA_NAME defined by a statement. */
@@ -1562,8 +1441,9 @@ ipa_note_param_call (struct cgraph_node
cs = cgraph_edge (node, stmt);
cs->indirect_info->param_index = param_index;
- cs->indirect_info->anc_offset = 0;
+ cs->indirect_info->offset = 0;
cs->indirect_info->polymorphic = 0;
+ cs->indirect_info->agg_contents = 0;
return cs;
}
@@ -1622,7 +1502,9 @@ ipa_note_param_call (struct cgraph_node
return (S.*f)(4);
}
-*/
+
+ Moreover, the function also looks for called pointers loaded from aggregates
+ passed by value or reference. */
static void
ipa_analyze_indirect_call_uses (struct cgraph_node *node,
@@ -1637,6 +1519,7 @@ ipa_analyze_indirect_call_uses (struct c
gimple branch;
int index;
basic_block bb, virt_bb, join;
+ HOST_WIDE_INT offset;
if (SSA_NAME_IS_DEFAULT_DEF (target))
{
@@ -1647,18 +1530,52 @@ ipa_analyze_indirect_call_uses (struct c
return;
}
- /* Now we need to try to match the complex pattern of calling a member
- pointer. */
+ def = SSA_NAME_DEF_STMT (target);
+ if (gimple_assign_single_p (def))
+ {
+ struct cgraph_edge *cs;
+ HOST_WIDE_INT size, max_size;
+ tree base = get_ref_base_and_extent (gimple_assign_rhs1 (def),
+ &offset, &size, &max_size);
+ if (max_size == -1 || max_size != size || offset < 0)
+ return;
- if (!POINTER_TYPE_P (TREE_TYPE (target))
- || TREE_CODE (TREE_TYPE (TREE_TYPE (target))) != METHOD_TYPE)
- return;
+ if (DECL_P (base))
+ {
+ index = ipa_get_param_decl_index (info, base);
+ if (index < 0 || !is_parm_preserved_before_stmt (&parms_ainfo[index],
+ call, base))
+ return;
+ }
+ else if (TREE_CODE (base) == MEM_REF
+ && TREE_CODE (TREE_OPERAND (base, 0)) == SSA_NAME
+ && SSA_NAME_IS_DEFAULT_DEF (TREE_OPERAND (base, 0))
+ && integer_zerop (TREE_OPERAND (base, 1)))
+ {
- def = SSA_NAME_DEF_STMT (target);
- if (gimple_code (def) != GIMPLE_PHI)
- return;
+ index = ipa_get_param_decl_index (info,
+ SSA_NAME_VAR (TREE_OPERAND (base,
+ 0)));
+ if (index < 0 || !is_parm_ref_data_preserved (&parms_ainfo[index],
+ call,
+ TREE_OPERAND (base, 0)))
+ return;
+ }
+ else
+ return;
+
+ cs = ipa_note_param_call (node, index, call);
+ cs->indirect_info->offset = offset;
+ cs->indirect_info->agg_contents = 1;
+ return;
+ }
- if (gimple_phi_num_args (def) != 2)
+ /* Now we need to try to match the complex pattern of calling a member
+ pointer. */
+ if (gimple_code (def) != GIMPLE_PHI
+ || gimple_phi_num_args (def) != 2
+ || !POINTER_TYPE_P (TREE_TYPE (target))
+ || TREE_CODE (TREE_TYPE (TREE_TYPE (target))) != METHOD_TYPE)
return;
/* First, we need to check whether one of these is a load from a member
@@ -1671,15 +1588,15 @@ ipa_analyze_indirect_call_uses (struct c
d2 = SSA_NAME_DEF_STMT (n2);
join = gimple_bb (def);
- if ((rec = ipa_get_stmt_member_ptr_load_param (d1, false)))
+ if ((rec = ipa_get_stmt_member_ptr_load_param (d1, false, &offset)))
{
- if (ipa_get_stmt_member_ptr_load_param (d2, false))
+ if (ipa_get_stmt_member_ptr_load_param (d2, false, NULL))
return;
bb = EDGE_PRED (join, 0)->src;
virt_bb = gimple_bb (d2);
}
- else if ((rec = ipa_get_stmt_member_ptr_load_param (d2, false)))
+ else if ((rec = ipa_get_stmt_member_ptr_load_param (d2, false, &offset)))
{
bb = EDGE_PRED (join, 1)->src;
virt_bb = gimple_bb (d1);
@@ -1734,15 +1651,19 @@ ipa_analyze_indirect_call_uses (struct c
rec2 = ipa_get_stmt_member_ptr_load_param (def,
(TARGET_PTRMEMFUNC_VBIT_LOCATION
- == ptrmemfunc_vbit_in_delta));
-
+ == ptrmemfunc_vbit_in_delta),
+ NULL);
if (rec != rec2)
return;
index = ipa_get_param_decl_index (info, rec);
if (index >= 0 && is_parm_preserved_before_stmt (&parms_ainfo[index],
call, rec))
- ipa_note_param_call (node, index, call);
+ {
+ struct cgraph_edge *cs = ipa_note_param_call (node, index, call);
+ cs->indirect_info->offset = offset;
+ cs->indirect_info->agg_contents = 1;
+ }
return;
}
@@ -1797,7 +1718,7 @@ ipa_analyze_virtual_call_uses (struct cg
cs = ipa_note_param_call (node, index, call);
ii = cs->indirect_info;
- ii->anc_offset = anc_offset;
+ ii->offset = anc_offset;
ii->otr_token = tree_low_cst (OBJ_TYPE_REF_TOKEN (target), 1);
ii->otr_type = TREE_TYPE (TREE_TYPE (OBJ_TYPE_REF_OBJECT (target)));
ii->polymorphic = 1;
@@ -2191,6 +2112,41 @@ ipa_make_edge_direct_to_target (struct c
return ie;
}
+/* Provided that values from AGG can be propagated to parameter of NODE with
+ index PARAM_INDEX so that is_parm_ref_data_preserved results are reliable
+ and that there is a known constant value in AGG the given OFFSET, return
+ the nown constant value. */
+
+tree
+ipa_find_agg_cst_for_param (struct ipa_agg_jump_function *agg,
+ HOST_WIDE_INT offset,
+ struct cgraph_node *node,
+ int param_index)
+{
+ struct ipa_node_params *info = IPA_NODE_REF (node);
+ tree t = TREE_TYPE (ipa_get_param (info, param_index));
+ struct ipa_agg_jf_item *item;
+ int i;
+
+ if (!agg->items
+ || !ipa_agg_types_propagatable_p (agg, t, 0))
+ return NULL;
+
+ FOR_EACH_VEC_ELT (ipa_agg_jf_item_t, agg->items, i, item)
+ {
+ if (item->offset == offset)
+ {
+ /* CUrrently we do not have clobber values, return NULL fro them once
+ we do. */
+ gcc_checking_assert (is_gimple_ip_invariant (item->value));
+ return item->value;
+ }
+ else if (item->offset > offset)
+ return NULL;
+ }
+ return NULL;
+}
+
/* Try to find a destination for indirect edge IE that corresponds to a simple
call or a call of a member function pointer and where the destination is a
pointer formal parameter described by jump function JFUNC. If it can be
@@ -2198,17 +2154,24 @@ ipa_make_edge_direct_to_target (struct c
static struct cgraph_edge *
try_make_edge_direct_simple_call (struct cgraph_edge *ie,
- struct ipa_jump_func *jfunc)
+ struct ipa_jump_func *jfunc, int param_index)
{
tree target;
- if (jfunc->type == IPA_JF_CONST)
- target = ipa_get_jf_constant (jfunc);
- else if (jfunc->type == IPA_JF_CONST_MEMBER_PTR)
- target = ipa_get_jf_member_ptr_pfn (jfunc);
+ if (ie->indirect_info->agg_contents)
+ {
+ target = ipa_find_agg_cst_for_param (&jfunc->agg,
+ ie->indirect_info->offset,
+ ie->caller, param_index);
+ if (!target)
+ return NULL;
+ }
else
- return NULL;
-
+ {
+ if (jfunc->type != IPA_JF_CONST)
+ return NULL;
+ target = ipa_get_jf_constant (jfunc);
+ }
return ipa_make_edge_direct_to_target (ie, target);
}
@@ -2229,7 +2192,7 @@ try_make_edge_direct_virtual_call (struc
binfo = TYPE_BINFO (ipa_get_jf_known_type_base_type (jfunc));
gcc_checking_assert (binfo);
binfo = get_binfo_at_offset (binfo, ipa_get_jf_known_type_offset (jfunc)
- + ie->indirect_info->anc_offset,
+ + ie->indirect_info->offset,
ie->indirect_info->otr_type);
if (binfo)
target = gimple_get_virt_method_for_binfo (ie->indirect_info->otr_token,
@@ -2265,6 +2228,7 @@ update_indirect_edges_after_inlining (st
{
struct cgraph_indirect_call_info *ici = ie->indirect_info;
struct ipa_jump_func *jfunc;
+ int param_index;
next_ie = ie->next_callee;
@@ -2278,14 +2242,15 @@ update_indirect_edges_after_inlining (st
continue;
}
- jfunc = ipa_get_ith_jump_func (top, ici->param_index);
+ param_index = ici->param_index;
+ jfunc = ipa_get_ith_jump_func (top, param_index);
if (jfunc->type == IPA_JF_PASS_THROUGH
&& ipa_get_jf_pass_through_operation (jfunc) == NOP_EXPR)
ici->param_index = ipa_get_jf_pass_through_formal_id (jfunc);
else if (jfunc->type == IPA_JF_ANCESTOR)
{
ici->param_index = ipa_get_jf_ancestor_formal_id (jfunc);
- ici->anc_offset += ipa_get_jf_ancestor_offset (jfunc);
+ ici->offset += ipa_get_jf_ancestor_offset (jfunc);
}
else
/* Either we can find a destination for this edge now or never. */
@@ -2297,7 +2262,8 @@ update_indirect_edges_after_inlining (st
if (ici->polymorphic)
new_direct_edge = try_make_edge_direct_virtual_call (ie, jfunc);
else
- new_direct_edge = try_make_edge_direct_simple_call (ie, jfunc);
+ new_direct_edge = try_make_edge_direct_simple_call (ie, jfunc,
+ param_index);
if (new_direct_edge)
{
@@ -3207,10 +3173,6 @@ ipa_write_jump_function (struct output_b
bp_pack_value (&bp, jump_func->value.ancestor.agg_preserved, 1);
streamer_write_bitpack (&bp);
break;
- case IPA_JF_CONST_MEMBER_PTR:
- stream_write_tree (ob, jump_func->value.member_cst.pfn, true);
- stream_write_tree (ob, jump_func->value.member_cst.delta, false);
- break;
}
count = VEC_length (ipa_agg_jf_item_t, jump_func->agg.items);
@@ -3263,10 +3225,6 @@ ipa_read_jump_function (struct lto_input
bp = streamer_read_bitpack (ib);
jump_func->value.ancestor.agg_preserved = bp_unpack_value (&bp, 1);
break;
- case IPA_JF_CONST_MEMBER_PTR:
- jump_func->value.member_cst.pfn = stream_read_tree (ib, data_in);
- jump_func->value.member_cst.delta = stream_read_tree (ib, data_in);
- break;
}
count = streamer_read_uhwi (ib);
@@ -3294,9 +3252,10 @@ ipa_write_indirect_edge_info (struct out
struct bitpack_d bp;
streamer_write_hwi (ob, ii->param_index);
- streamer_write_hwi (ob, ii->anc_offset);
+ streamer_write_hwi (ob, ii->offset);
bp = bitpack_create (ob->main_stream);
bp_pack_value (&bp, ii->polymorphic, 1);
+ bp_pack_value (&bp, ii->agg_contents, 1);
streamer_write_bitpack (&bp);
if (ii->polymorphic)
@@ -3318,9 +3277,10 @@ ipa_read_indirect_edge_info (struct lto_
struct bitpack_d bp;
ii->param_index = (int) streamer_read_hwi (ib);
- ii->anc_offset = (HOST_WIDE_INT) streamer_read_hwi (ib);
+ ii->offset = (HOST_WIDE_INT) streamer_read_hwi (ib);
bp = streamer_read_bitpack (ib);
ii->polymorphic = bp_unpack_value (&bp, 1);
+ ii->agg_contents = bp_unpack_value (&bp, 1);
if (ii->polymorphic)
{
ii->otr_token = (HOST_WIDE_INT) streamer_read_hwi (ib);
===================================================================
@@ -44,10 +44,6 @@ along with GCC; see the file COPYING3.
argument.
Unknown - neither of the above.
- IPA_JF_CONST_MEMBER_PTR stands for C++ member pointers, it is a special
- constant in this regard because it is in fact a structure consisting of two
- values. Other constants are represented with IPA_JF_CONST.
-
IPA_JF_ANCESTOR is a special pass-through jump function, which means that
the result is an address of a part of the object pointed to by the formal
parameter to which the function refers. It is mainly intended to represent
@@ -74,7 +70,6 @@ enum jump_func_type
IPA_JF_UNKNOWN = 0, /* newly allocated and zeroed jump functions default */
IPA_JF_KNOWN_TYPE, /* represented by field known_type */
IPA_JF_CONST, /* represented by field costant */
- IPA_JF_CONST_MEMBER_PTR, /* represented by field member_cst */
IPA_JF_PASS_THROUGH, /* represented by field pass_through */
IPA_JF_ANCESTOR /* represented by field ancestor */
};
@@ -128,14 +123,6 @@ struct GTY(()) ipa_ancestor_jf_data
bool agg_preserved;
};
-/* Structure holding a C++ member pointer constant. Holds a pointer to the
- method and delta offset. */
-struct GTY(()) ipa_member_ptr_cst
-{
- tree pfn;
- tree delta;
-};
-
/* An element in an aggegate part of a jump function describing a known value
at a given offset. When the this is part of a pass-through jump function
with agg_preserved set or an ancestor jump function with agg_preserved set,
@@ -191,7 +178,6 @@ typedef struct GTY (()) ipa_jump_func
{
struct ipa_known_type_data GTY ((tag ("IPA_JF_KNOWN_TYPE"))) known_type;
tree GTY ((tag ("IPA_JF_CONST"))) constant;
- struct ipa_member_ptr_cst GTY ((tag ("IPA_JF_CONST_MEMBER_PTR"))) member_cst;
struct ipa_pass_through_data GTY ((tag ("IPA_JF_PASS_THROUGH"))) pass_through;
struct ipa_ancestor_jf_data GTY ((tag ("IPA_JF_ANCESTOR"))) ancestor;
} GTY ((desc ("%1.type"))) value;
@@ -311,14 +297,10 @@ ipa_get_jf_ancestor_agg_preserved (struc
return jfunc->value.ancestor.agg_preserved;
}
-/* Return the pfn part of a member pointer constant jump function JFUNC. */
+/* Aggregate jump function related functions. */
+tree ipa_find_agg_cst_for_param (struct ipa_agg_jump_function *, HOST_WIDE_INT,
+ struct cgraph_node *, int);
-static inline tree
-ipa_get_jf_member_ptr_pfn (struct ipa_jump_func *jfunc)
-{
- gcc_checking_assert (jfunc->type == IPA_JF_CONST_MEMBER_PTR);
- return jfunc->value.member_cst.pfn;
-}
/* Summary describing a single formal parameter. */
===================================================================
@@ -1110,7 +1110,7 @@ ipa_get_indirect_edge_target (struct cgr
}
token = ie->indirect_info->otr_token;
- anc_offset = ie->indirect_info->anc_offset;
+ anc_offset = ie->indirect_info->offset;
otr_type = ie->indirect_info->otr_type;
t = VEC_index (tree, known_vals, param_index);
===================================================================
@@ -0,0 +1,87 @@
+/* Verify that simple indirect calls are inlined even without early
+ inlining.. */
+/* { dg-do compile } */
+/* { dg-options "-O3 -c -fdump-ipa-inline -fno-early-inlining" } */
+
+struct S
+{
+ int i;
+ void (*f)(struct S *);
+ char c;
+};
+
+extern void non_existent(struct S *p, int);
+
+static void hooray1 (struct S *p)
+{
+ non_existent (p, 1);
+}
+
+static void hiphip1 (struct S *p)
+{
+ p->f (p);
+}
+
+int test1 (void)
+{
+ struct S s;
+ s.i = 1234;
+ s.f = hooray1;
+ s.c = 'c';
+ hiphip1 (&s);
+ return 0;
+}
+
+struct S gs;
+struct S *gp = &gs;
+
+static void hooray2 (struct S *p)
+{
+ non_existent (p, 2);
+}
+
+static void hip2 (struct S *p)
+{
+ p->f (p);
+}
+
+static void hiphip2 (struct S *p)
+{
+ hip2 (p);
+}
+
+int test2 (void)
+{
+ struct S *p = gp;
+ p->i = 2341;
+ p->f = hooray2;
+ p->c = 'c';
+ hiphip2 (p);
+ return 0;
+}
+
+static void hooray3 (struct S *p)
+{
+ non_existent (p, 3);
+}
+
+static void hiphip3 (struct S s)
+{
+ s.f (&s);
+}
+
+int test3(void)
+{
+ struct S s;
+ s.i = 3412;
+ s.f = hooray3;
+ s.c = 'c';
+ hiphip3 (s);
+ return 0;
+}
+
+
+/* { dg-final { scan-ipa-dump "hooray1\[^\\n\]*inline copy in test1" "inline" } } */
+/* { dg-final { scan-ipa-dump "hooray2\[^\\n\]*inline copy in test2" "inline" } } */
+/* { dg-final { scan-ipa-dump "hooray2\[^\\n\]*inline copy in test2" "inline" } } */
+/* { dg-final { cleanup-ipa-dump "inline" } } */