Hi, this patch solves the actual ICE in PR59831 by using ipa-devirt instead of gimple_extract_devirt_binfo_from_cst as discussed in the first post.
Honza PR ipa/59831 * ipa-cp.c (ipa_get_indirect_edge_target_1): Use ipa-devirt to figure out targets of polymorphic calls with known decl. * ipa-prop.c (try_make_edge_direct_virtual_call): Likewise. * ipa-utils.h (get_polymorphic_call_info_from_invariant): Declare. * ipa-devirt.c (get_polymorphic_call_info_for_decl): Break out from ... (get_polymorphic_call_info): ... here. (get_polymorphic_call_info_from_invariant): New function. * g++.dg/ipa/devirt-22.C: New testcase. Index: ipa-cp.c =================================================================== --- ipa-cp.c (revision 207447) +++ ipa-cp.c (working copy) @@ -1601,15 +1601,24 @@ ipa_get_indirect_edge_target_1 (struct c if (TREE_CODE (t) != TREE_BINFO) { - tree binfo; - binfo = gimple_extract_devirt_binfo_from_cst - (t, ie->indirect_info->otr_type); - if (!binfo) + ipa_polymorphic_call_context context; + vec <cgraph_node *>targets; + bool final; + + if (!get_polymorphic_call_info_from_invariant + (&context, t, ie->indirect_info->otr_type, + anc_offset)) return NULL_TREE; - binfo = get_binfo_at_offset (binfo, anc_offset, otr_type); - if (!binfo) + targets = possible_polymorphic_call_targets + (ie->indirect_info->otr_type, + ie->indirect_info->otr_token, + context, &final); + if (!final || targets.length () > 1) return NULL_TREE; - target = gimple_get_virt_method_for_binfo (token, binfo); + if (targets.length () == 1) + target = targets[0]->decl; + else + target = builtin_decl_implicit (BUILT_IN_UNREACHABLE); } else { Index: testsuite/g++.dg/ipa/devirt-22.C =================================================================== --- testsuite/g++.dg/ipa/devirt-22.C (revision 0) +++ testsuite/g++.dg/ipa/devirt-22.C (revision 0) @@ -0,0 +1,41 @@ +/* { dg-do compile } */ +/* { dg-options "-O3 -fno-early-inlining -fno-ipa-sra -fdump-ipa-cp" } */ +class A {}; +class B { +public: + A &operator[](int); +}; +class C : B { +public: + virtual int m_fn1() { return 0; } + A &operator[](int p1) { + int a; + a = m_fn1(); + static_cast<void>(__builtin_expect(a, 0) ?: 0); + return B::operator[](p1); + } +}; + +C b; +int *e; +static void sort(C &p1, C &p2) { + for (int i=0;; i++) { + A c, d = p2[0]; + p1[0] = c; + p2[0] = d; + } +} + +void lookupSourceDone() { b[0]; } + +void update_sources() { + if (e) { + C f; + sort(f, b); + } +} +/* Note that we miss one devirtualization because we are not able to track the + vtbl store in destructor. + Previously we devirtualized to C::m_fn1 instead of B::m_fn1. */ +/* { dg-final { scan-tree-dump-times "Discovered a virtual call to a known target" 1 "cp" } } */ +/* { dg-final { cleanup-ipa-dump "cp" } } */ Index: ipa-utils.h =================================================================== --- ipa-utils.h (revision 207439) +++ ipa-utils.h (working copy) @@ -87,6 +87,8 @@ tree method_class_type (tree); tree get_polymorphic_call_info (tree, tree, tree *, HOST_WIDE_INT *, ipa_polymorphic_call_context *); +bool get_polymorphic_call_info_from_invariant (ipa_polymorphic_call_context *, + tree, tree, HOST_WIDE_INT); tree vtable_pointer_value_to_binfo (tree t); bool vtable_pointer_value_to_vtable (tree, tree *, unsigned HOST_WIDE_INT *); Index: ipa-prop.c =================================================================== --- ipa-prop.c (revision 207447) +++ ipa-prop.c (working copy) @@ -2731,19 +2731,38 @@ try_make_edge_direct_virtual_call (struc if (TREE_CODE (binfo) != TREE_BINFO) { - binfo = gimple_extract_devirt_binfo_from_cst - (binfo, ie->indirect_info->otr_type); - if (!binfo) + ipa_polymorphic_call_context context; + vec <cgraph_node *>targets; + bool final; + + if (!get_polymorphic_call_info_from_invariant + (&context, binfo, ie->indirect_info->otr_type, + ie->indirect_info->offset)) + return NULL; + targets = possible_polymorphic_call_targets + (ie->indirect_info->otr_type, + ie->indirect_info->otr_token, + context, &final); + if (!final || targets.length () > 1) return NULL; + if (targets.length () == 1) + target = targets[0]->decl; + else + { + target = builtin_decl_implicit (BUILT_IN_UNREACHABLE); + cgraph_get_create_node (target); + } } - - binfo = get_binfo_at_offset (binfo, ie->indirect_info->offset, - ie->indirect_info->otr_type); - if (binfo) - target = gimple_get_virt_method_for_binfo (ie->indirect_info->otr_token, - binfo); else - return NULL; + { + binfo = get_binfo_at_offset (binfo, ie->indirect_info->offset, + ie->indirect_info->otr_type); + if (binfo) + target = gimple_get_virt_method_for_binfo (ie->indirect_info->otr_token, + binfo); + else + return NULL; + } if (target) { Index: ipa-devirt.c =================================================================== --- ipa-devirt.c (revision 207439) +++ ipa-devirt.c (working copy) @@ -1071,6 +1071,60 @@ vtable_pointer_value_to_binfo (tree t) offset, vtable); } +/* Proudce polymorphic call context for call method of instance + that is located within BASE (that is assumed to be a decl) at OFFSET. */ + +static void +get_polymorphic_call_info_for_decl (ipa_polymorphic_call_context *context, + tree base, HOST_WIDE_INT offset) +{ + gcc_assert (DECL_P (base)); + + context->outer_type = TREE_TYPE (base); + context->offset = offset; + /* Make very conservative assumption that all objects + may be in construction. + TODO: ipa-prop already contains code to tell better. + merge it later. */ + context->maybe_in_construction = true; + context->maybe_derived_type = false; +} + +/* CST is an invariant (address of decl), try to get meaningful + polymorphic call context for polymorphic call of method + if instance of OTR_TYPE that is located at OFFSET of this invariant. + Return FALSE if nothing meaningful can be found. */ + +bool +get_polymorphic_call_info_from_invariant (ipa_polymorphic_call_context *context, + tree cst, + tree otr_type, + HOST_WIDE_INT offset) +{ + HOST_WIDE_INT offset2, size, max_size; + tree base; + + if (TREE_CODE (cst) != ADDR_EXPR) + return NULL_TREE; + + cst = TREE_OPERAND (cst, 0); + base = get_ref_base_and_extent (cst, &offset2, &size, &max_size); + if (!DECL_P (base) + || max_size == -1 + || max_size != size) + return NULL_TREE; + + /* Only type inconsistent programs can have otr_type that is + not part of outer type. */ + if (!contains_type_p (TREE_TYPE (base), + offset, otr_type)) + return NULL_TREE; + + get_polymorphic_call_info_for_decl (context, + base, offset); + return true; +} + /* Given REF call in FNDECL, determine class of the polymorphic call (OTR_TYPE), its token (OTR_TOKEN) and CONTEXT. Return pointer to object described by the context */ @@ -1136,14 +1190,8 @@ get_polymorphic_call_info (tree fndecl, if (!contains_type_p (TREE_TYPE (base), context->offset + offset2, *otr_type)) return base_pointer; - context->outer_type = TREE_TYPE (base); - context->offset += offset2; - /* Make very conservative assumption that all objects - may be in construction. - TODO: ipa-prop already contains code to tell better. - merge it later. */ - context->maybe_in_construction = true; - context->maybe_derived_type = false; + get_polymorphic_call_info_for_decl (context, base, + context->offset + offset2); return NULL; } else