{
struct ipcp_lattice *caller_lat;
tree t;
- bool ok;
caller_lat = ipcp_get_lattice (info, jfunc->value.ancestor.formal_id);
lat->type = caller_lat->type;
return;
}
t = TREE_OPERAND (caller_lat->constant, 0);
- ok = build_ref_for_offset (&t, TREE_TYPE (t),
- jfunc->value.ancestor.offset,
- jfunc->value.ancestor.type, false);
- if (!ok)
- {
- lat->type = IPA_BOTTOM;
- lat->constant = NULL_TREE;
- }
- else
- lat->constant = build_fold_addr_expr (t);
+ t = build_ref_for_offset (EXPR_LOCATION (t), t,
+ jfunc->value.ancestor.offset,
+ jfunc->value.ancestor.type, NULL, false);
+ lat->constant = build_fold_addr_expr (t);
}
else
lat->type = IPA_BOTTOM;
{
struct cgraph_edge *edge;
- /* There are a number of generic reasons functions cannot be versioned. */
- if (!node->local.versionable)
+ /* There are a number of generic reasons functions cannot be versioned. We
+ also cannot remove parameters if there are type attributes such as fnspec
+ present. */
+ if (!node->local.versionable
+ || TYPE_ATTRIBUTES (TREE_TYPE (node->decl)))
return false;
/* Removing arguments doesn't work if the function takes varargs
if (cgraph_only_called_directly_p (node) || !node->analyzed)
return false;
+ /* When function address is taken, we are pretty sure it will be called in hidden way. */
+ if (node->address_taken)
+ {
+ if (dump_file)
+ fprintf (dump_file, "Not considering %s for cloning; address is taken.\n",
+ cgraph_node_name (node));
+ return false;
+ }
+
if (cgraph_function_body_availability (node) <= AVAIL_OVERWRITABLE)
{
if (dump_file)
if (ipa_is_called_with_var_arguments (info))
type = IPA_BOTTOM;
- else if (cgraph_only_called_directly_p (node))
+ else if (node->local.local)
type = IPA_TOP;
/* When cloning is allowed, we can assume that externally visible functions
are not called. We will compensate this by cloning later. */
return const_param;
}
+/* Given that a formal parameter of NODE given by INDEX is known to be constant
+ CST, try to find any indirect edges that can be made direct and make them
+ so. Note that INDEX is the number the parameter at the time of analyzing
+ parameter uses and parameter removals should not be considered for it. (In
+ fact, the parameter itself has just been removed.) */
+
+static void
+ipcp_discover_new_direct_edges (struct cgraph_node *node, int index, tree cst)
+{
+ struct cgraph_edge *ie, *next_ie;
+
+ for (ie = node->indirect_calls; ie; ie = next_ie)
+ {
+ struct cgraph_indirect_call_info *ici = ie->indirect_info;
+
+ next_ie = ie->next_callee;
+ if (ici->param_index != index)
+ continue;
+
+ if (ici->polymorphic)
+ {
+ tree binfo;
+ HOST_WIDE_INT token;
+
+ if (TREE_CODE (cst) != ADDR_EXPR)
+ continue;
+
+ binfo = gimple_get_relevant_ref_binfo (TREE_OPERAND (cst, 0),
+ NULL_TREE);
+ if (!binfo)
+ 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)
+ continue;
+ }
+
+ ipa_make_edge_direct_to_target (ie, cst);
+ }
+}
+
+
/* Propagate the constant parameters found by ipcp_iterate_stage()
to the function's code. */
static void
node_callers++;
redirect_callers = VEC_alloc (cgraph_edge_p, heap, node_callers);
for (cs = node->callers; cs != NULL; cs = cs->next_caller)
- VEC_quick_push (cgraph_edge_p, redirect_callers, cs);
+ if (!cs->indirect_inlining_edge)
+ VEC_quick_push (cgraph_edge_p, redirect_callers, cs);
/* Redirecting all the callers of the node to the
new versioned node. */
cgraph_node_name (node), (int)growth, (int)new_size);
ipcp_init_cloned_node (node, node1);
- /* TODO: We can use indirect inlning info to produce new calls. */
+ info = IPA_NODE_REF (node);
+ for (i = 0; i < count; i++)
+ {
+ struct ipcp_lattice *lat = ipcp_get_lattice (info, i);
+ if (lat->type == IPA_CONST_VALUE)
+ ipcp_discover_new_direct_edges (node1, i, lat->constant);
+ }
if (dump_file)
dump_function_to_file (node1->decl, dump_file, dump_flags);