return false;
}
+/* Return true, if JFUNC, which describes a part of an aggregate represented
+ or pointed to by the i-th parameter of call CS, is a simple no-operation
+ pass-through function to itself. */
+
+static bool
+self_recursive_agg_pass_through_p (cgraph_edge *cs, ipa_agg_jf_item *jfunc,
+ int i)
+{
+ enum availability availability;
+ if (cs->caller == cs->callee->function_symbol (&availability)
+ && availability > AVAIL_INTERPOSABLE
+ && jfunc->jftype == IPA_JF_LOAD_AGG
+ && jfunc->offset == jfunc->value.load_agg.offset
+ && jfunc->value.pass_through.operation == NOP_EXPR
+ && jfunc->value.pass_through.formal_id == i)
+ return true;
+ return false;
+}
+
/* Given a NODE, and a subset of its CALLERS, try to populate blanks slots in
KNOWN_CSTS with constants that are also known for all of the CALLERS. */
if (aglat->offset - offset == item->offset)
{
gcc_checking_assert (item->value);
- if (aglat->is_single_const ()
- && values_equal_for_ipcp_p (item->value,
- aglat->values->value))
- found = true;
+ if (aglat->is_single_const ())
+ {
+ tree value = aglat->values->value;
+
+ if (values_equal_for_ipcp_p (item->value, value))
+ found = true;
+ else if (item->value == error_mark_node)
+ {
+ /* Replace unknown place holder value with real one. */
+ item->value = value;
+ found = true;
+ }
+ }
break;
}
aglat = aglat->next;
{
if (values_equal_for_ipcp_p (item->value, av->value))
found = true;
+ else if (item->value == error_mark_node)
+ {
+ /* Replace place holder value with real one. */
+ item->value = av->value;
+ found = true;
+ }
break;
}
}
for (unsigned i = 0; i < jfunc->agg.items->length (); i++)
{
struct ipa_agg_jf_item *agg_item = &(*jfunc->agg.items)[i];
- tree value = ipa_agg_value_from_node (caller_info, cs->caller,
- agg_item);
- if (value)
+ struct ipa_agg_value agg_value;
+
+ if (self_recursive_agg_pass_through_p (cs, agg_item, index))
{
- struct ipa_agg_value agg_value;
+ /* For a self-recursive call, if aggregate jump function is a
+ simple pass-through, the exact value that it stands for is
+ not known at this point, which must comes from other call
+ sites. But we still need to add a place holder in value
+ sets to indicate it, here we use error_mark_node to
+ represent the special unknown value, which will be replaced
+ with real one during later intersecting operations. */
+ agg_value.value = error_mark_node;
+ }
+ else
+ {
+ tree value = ipa_agg_value_from_node (caller_info, cs->caller,
+ agg_item);
+ if (!value)
+ continue;
- agg_value.offset = agg_item->offset;
agg_value.value = value;
-
- inter.safe_push (agg_value);
}
+
+ agg_value.offset = agg_item->offset;
+ inter.safe_push (agg_value);
}
else
FOR_EACH_VEC_ELT (inter, k, item)
break;
if (ti->offset == item->offset)
{
- tree value = ipa_agg_value_from_node (caller_info,
- cs->caller, ti);
- if (value
- && values_equal_for_ipcp_p (item->value, value))
- found = true;
+ tree value;
+
+ if (self_recursive_agg_pass_through_p (cs, ti, index))
+ {
+ /* A simple aggregate pass-through in self-recursive
+ call should lead to same value. */
+ found = true;
+ }
+ else if ((value = ipa_agg_value_from_node (caller_info,
+ cs->caller, ti)))
+ {
+ if (values_equal_for_ipcp_p (item->value, value))
+ found = true;
+ else if (item->value == error_mark_node)
+ {
+ /* Replace unknown place holder value with real
+ one. */
+ item->value = value;
+ found = true;
+ }
+ }
break;
}
l++;
if (!item->value)
continue;
+ /* All values must be real values, not unknown place holders. */
+ gcc_assert (item->value != error_mark_node);
+
v = ggc_alloc<ipa_agg_replacement_value> ();
v->index = i;
v->offset = item->offset;