ipa-cp: Also look at self-recursive ancestor jump functions (PR122856)

PR 122856 shows that when looking at self recursive calls with
self-feeding jump functions, we did consider pass-through functions
but not ancestor functions with zero offsets.  This then leads to the
fact that constants which were collected from IPA-CP lattices were not
among those collected from available edges, triggering a verification
assert.

This patch fixes that by also detecting self-feeding ancestor jump
functions.

gcc/ChangeLog:

2026-02-06  Martin Jambor  <mjambor@suse.cz>

	PR ipa/122856
	* ipa-cp.cc (self_recursive_pass_through_p): Test jump function type first.
	(self_recursive_ancestor_p): New function.
	(find_scalar_values_for_callers_subset): Test also for self-recursive
	ancestor jump functions.
	(push_agg_values_for_index_from_edge): Likewise.

gcc/testsuite/ChangeLog:

2026-02-06  Martin Jambor  <mjambor@suse.cz>

	PR ipa/122856
	* g++.dg/ipa/pr122856.C: New test.
This commit is contained in:
Martin Jambor
2026-02-20 14:34:27 +01:00
committed by Martin Jambor
parent 8d8725bedd
commit e47f44074a
2 changed files with 51 additions and 3 deletions

View File

@@ -5259,9 +5259,9 @@ self_recursive_pass_through_p (cgraph_edge *cs, ipa_jump_func *jfunc, int i,
bool simple = true) bool simple = true)
{ {
enum availability availability; enum availability availability;
if (cs->caller == cs->callee->function_symbol (&availability) if (jfunc->type == IPA_JF_PASS_THROUGH
&& cs->caller == cs->callee->function_symbol (&availability)
&& availability > AVAIL_INTERPOSABLE && availability > AVAIL_INTERPOSABLE
&& jfunc->type == IPA_JF_PASS_THROUGH
&& (!simple || ipa_get_jf_pass_through_operation (jfunc) == NOP_EXPR) && (!simple || ipa_get_jf_pass_through_operation (jfunc) == NOP_EXPR)
&& ipa_get_jf_pass_through_formal_id (jfunc) == i && ipa_get_jf_pass_through_formal_id (jfunc) == i
&& ipa_node_params_sum->get (cs->caller) && ipa_node_params_sum->get (cs->caller)
@@ -5270,6 +5270,25 @@ self_recursive_pass_through_p (cgraph_edge *cs, ipa_jump_func *jfunc, int i,
return false; return false;
} }
/* Return true if JFUNC, which describes the i-th parameter of call CS, is an
ancestor function with zero offset to itself when the cgraph_node involved
is not an IPA-CP clone. */
static bool
self_recursive_ancestor_p (cgraph_edge *cs, ipa_jump_func *jfunc, int i)
{
enum availability availability;
if (jfunc->type == IPA_JF_ANCESTOR
&& cs->caller == cs->callee->function_symbol (&availability)
&& availability > AVAIL_INTERPOSABLE
&& ipa_get_jf_ancestor_offset (jfunc) == 0
&& ipa_get_jf_ancestor_formal_id (jfunc) == i
&& ipa_node_params_sum->get (cs->caller)
&& !ipa_node_params_sum->get (cs->caller)->ipcp_orig_node)
return true;
return false;
}
/* Return true if JFUNC, which describes a part of an aggregate represented or /* 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 pass-through function to pointed to by the i-th parameter of call CS, is a pass-through function to
itself when the cgraph_node involved is not an IPA-CP clone.. When itself when the cgraph_node involved is not an IPA-CP clone.. When
@@ -5361,6 +5380,8 @@ find_scalar_values_for_callers_subset (vec<tree> &known_csts,
op_type); op_type);
t = ipacp_value_safe_for_type (type, t); t = ipacp_value_safe_for_type (type, t);
} }
else if (self_recursive_ancestor_p (cs, jump_func, i))
continue;
else else
t = ipa_value_from_jfunc (ipa_node_params_sum->get (cs->caller), t = ipa_value_from_jfunc (ipa_node_params_sum->get (cs->caller),
jump_func, type); jump_func, type);
@@ -5515,7 +5536,8 @@ push_agg_values_for_index_from_edge (struct cgraph_edge *cs, int index,
&& !src_plats->aggs_bottom && !src_plats->aggs_bottom
&& (agg_jf_preserved || !src_plats->aggs_by_ref)) && (agg_jf_preserved || !src_plats->aggs_by_ref))
{ {
if (interim && self_recursive_pass_through_p (cs, jfunc, index)) if (interim && (self_recursive_pass_through_p (cs, jfunc, index)
|| self_recursive_ancestor_p (cs, jfunc, index)))
{ {
interim->push_adjusted_values (src_idx, index, unit_delta, interim->push_adjusted_values (src_idx, index, unit_delta,
res); res);

View File

@@ -0,0 +1,26 @@
/* { dg-do compile } */
/* { dg-options "-O3 -std=gnu++11" } */
template <typename T>
class Base {
public:
virtual int get();
virtual ~Base() = default;
};
template <typename T>
class Derived : public Base<T> {
public:
int get() override { return Base<T>::get(); }
};
template <typename T>
int Base<T>::get() {
return static_cast<Derived<int>*>(this)->get();
}
int main() {
Derived<int> d;
return d.get();
}