Hi, this patch fixes first part of PR58477. Here we miss IPA devirtualization opurtunity but produce speculative call. Later during inlining, the standard folders produce direct call and we ICE after cgraph_clone_edge messes up the speculative call info.
This patch makes cgraph_clone_edge to do the right thing. We however should fix the missed optimization, too. The testcase (I am not comitting since I want to deal with it incrementally is): Index: testsuite/g++.dg/torture/pr58477.C =================================================================== --- testsuite/g++.dg/torture/pr58477.C (revision 0) +++ testsuite/g++.dg/torture/pr58477.C (revision 0) @@ -0,0 +1,25 @@ +/* { dg-do compile } */ +struct A { + void operator==(const A &); +}; +class B { +public: + A m_fn1(); + A m_fn2(); +}; +template <typename T, typename M> class C { +public: + T Key; + const M &m_fn2(const T &); + virtual void m_fn1() {} + B _map; +}; + +C<int, int> b; +template <typename T, typename M> const M &C<T, M>::m_fn2(const T &) { + A a = _map.m_fn2(); + a == _map.m_fn1(); + m_fn1(); +} + +void fn1() { b.m_fn2(0); } And code in question: ;; Function const M& C<T, M>::m_fn2(const T&) [with T = int; M = int] (_ZN1CIiiE5m_fn2ERKi.isra.0, funcdef_no=10, decl_uid=2371, symbol_order=19) const M& C<T, M>::m_fn2(const T&) [with T = int; M = int] (struct C * const this) { struct A D.2376; struct A a; struct B * _2; int (*__vtbl_ptr_type) () * _3; int (*__vtbl_ptr_type) () _4; <bb 2>: _2 = &this_1(D)->_map; B::m_fn2 (_2); B::m_fn1 (_2); A::operator== (&a, &D.2376); D.2376 ={v} {CLOBBER}; _3 = this_1(D)->_vptr.C; _4 = *_3; OBJ_TYPE_REF(_4;(struct C)this_1(D)->0) (this_1(D)); a ={v} {CLOBBER}; return; } Where this is propagated into &b that is a static variable of given type. The reason why ipa-cp does not match is that it thinks the type may dynamically change. I think it can not since the function is method and I do not think methods except for ctors/dtors should have way to change type of their object. Martin, Jason, is there way to implement this logic into detect_type_change? In any case the stopper here is: D.2376 ={v} {CLOBBER}; that is stupid. I am testing followup patch that makes type change machinery to walk through clobbers. Bootstrapped/regtested x86_64-linux, will commit it shortly. Honza * cgraphclones.c (cgraph_clone_edge): Do not resolve speculative edges. Index: cgraphclones.c =================================================================== --- cgraphclones.c (revision 205987) +++ cgraphclones.c (working copy) @@ -123,7 +123,10 @@ cgraph_clone_edge (struct cgraph_edge *e { tree decl; - if (call_stmt && (decl = gimple_call_fndecl (call_stmt))) + if (call_stmt && (decl = gimple_call_fndecl (call_stmt)) + /* When the call is speculative, we need to resolve it + via cgraph_resolve_speculation and not here. */ + && !e->speculative) { struct cgraph_node *callee = cgraph_get_node (decl); gcc_checking_assert (callee);