Thanks, this is version I commited after testing at ppc64-linux. The difference is that it also updates code suffering from the same problem in gimple_extract_devirt_binfo_from_cst. I originally intended to rewrite the function but after yesterday discussion with Martin I think it will take me little more time. Moreover this really can trigger bad code so I think having self contained patch is better.
Honza * gimple-fold.c (gimple_extract_devirt_binfo_from_cst): Add new arugment expected_type. (gimple_fold_call): Use it. * gimple.h (gimple_extract_devirt_binfo_from_cst): Update prototype. * ipa-cp.c (ipa_get_indirect_edge_target_1): Update. * ipa-prop.c (ipa_analyze_virtual_call_uses): Use obj_type_ref_class. (try_make_edge_direct_virtual_call): Likewise. * tree.c (obj_type_ref_class): New. * tree.h (obj_type_ref_class): Use it. . Index: gimple-fold.c =================================================================== --- gimple-fold.c (revision 201776) +++ gimple-fold.c (working copy) @@ -1007,13 +1007,14 @@ gimple_fold_builtin (gimple stmt) represented by a declaration (i.e. a global or automatically allocated one) or NULL if it cannot be found or is not safe. CST is expected to be an ADDR_EXPR of such object or the function will return NULL. Currently it is - safe to use such binfo only if it has no base binfo (i.e. no ancestors). */ + safe to use such binfo only if it has no base binfo (i.e. no ancestors) + EXPECTED_TYPE is type of the class virtual belongs to. */ tree -gimple_extract_devirt_binfo_from_cst (tree cst) +gimple_extract_devirt_binfo_from_cst (tree cst, tree expected_type) { HOST_WIDE_INT offset, size, max_size; - tree base, type, expected_type, binfo; + tree base, type, binfo; bool last_artificial = false; if (!flag_devirtualize @@ -1022,7 +1023,6 @@ gimple_extract_devirt_binfo_from_cst (tr return NULL_TREE; cst = TREE_OPERAND (cst, 0); - expected_type = TREE_TYPE (cst); base = get_ref_base_and_extent (cst, &offset, &size, &max_size); type = TREE_TYPE (base); if (!DECL_P (base) @@ -1108,7 +1108,8 @@ gimple_fold_call (gimple_stmt_iterator * else { tree obj = OBJ_TYPE_REF_OBJECT (callee); - tree binfo = gimple_extract_devirt_binfo_from_cst (obj); + tree binfo = gimple_extract_devirt_binfo_from_cst + (obj, obj_type_ref_class (callee)); if (binfo) { HOST_WIDE_INT token Index: gimple.h =================================================================== --- gimple.h (revision 201776) +++ gimple.h (working copy) @@ -854,7 +854,7 @@ unsigned get_gimple_rhs_num_ops (enum tr gimple gimple_alloc_stat (enum gimple_code, unsigned MEM_STAT_DECL); const char *gimple_decl_printable_name (tree, int); tree gimple_get_virt_method_for_binfo (HOST_WIDE_INT, tree); -tree gimple_extract_devirt_binfo_from_cst (tree); +tree gimple_extract_devirt_binfo_from_cst (tree, tree); /* Returns true iff T is a scalar register variable. */ extern bool is_gimple_reg (tree); Index: ipa-cp.c =================================================================== --- ipa-cp.c (revision 201776) +++ ipa-cp.c (working copy) @@ -1541,7 +1541,8 @@ ipa_get_indirect_edge_target_1 (struct c if (TREE_CODE (t) != TREE_BINFO) { tree binfo; - binfo = gimple_extract_devirt_binfo_from_cst (t); + binfo = gimple_extract_devirt_binfo_from_cst + (t, ie->indirect_info->otr_type); if (!binfo) return NULL_TREE; binfo = get_binfo_at_offset (binfo, anc_offset, otr_type); Index: ipa-prop.c =================================================================== --- ipa-prop.c (revision 201776) +++ ipa-prop.c (working copy) @@ -1903,7 +1903,7 @@ ipa_analyze_virtual_call_uses (struct cg ii = cs->indirect_info; ii->offset = anc_offset; ii->otr_token = tree_low_cst (OBJ_TYPE_REF_TOKEN (target), 1); - ii->otr_type = TREE_TYPE (TREE_TYPE (OBJ_TYPE_REF_OBJECT (target))); + ii->otr_type = obj_type_ref_class (target); ii->polymorphic = 1; } @@ -2453,7 +2453,8 @@ try_make_edge_direct_virtual_call (struc if (TREE_CODE (binfo) != TREE_BINFO) { - binfo = gimple_extract_devirt_binfo_from_cst (binfo); + binfo = gimple_extract_devirt_binfo_from_cst + (binfo, ie->indirect_info->otr_type); if (!binfo) return NULL; } Index: tree.c =================================================================== --- tree.c (revision 201776) +++ tree.c (working copy) @@ -11864,6 +11864,21 @@ types_same_for_odr (tree type1, tree typ return true; } +/* REF is OBJ_TYPE_REF, return the class the ref corresponds to. */ + +tree +obj_type_ref_class (tree ref) +{ + gcc_checking_assert (TREE_CODE (ref) == OBJ_TYPE_REF); + ref = TREE_TYPE (ref); + gcc_checking_assert (TREE_CODE (ref) == POINTER_TYPE); + ref = TREE_TYPE (ref); + gcc_checking_assert (TREE_CODE (ref) == METHOD_TYPE); + ref = TREE_VALUE (TYPE_ARG_TYPES (ref)); + gcc_checking_assert (TREE_CODE (ref) == POINTER_TYPE); + return TREE_TYPE (ref); +} + /* Try to find a base info of BINFO that would have its field decl at offset OFFSET within the BINFO type and which is of EXPECTED_TYPE. If it can be found, return, otherwise return NULL_TREE. */ Index: tree.h =================================================================== --- tree.h (revision 201776) +++ tree.h (working copy) @@ -5974,6 +5974,7 @@ extern location_t tree_nonartificial_loc extern tree block_ultimate_origin (const_tree); extern tree get_binfo_at_offset (tree, HOST_WIDE_INT, tree); +extern tree obj_type_ref_class (tree ref); extern bool types_same_for_odr (tree type1, tree type2); extern tree get_ref_base_and_extent (tree, HOST_WIDE_INT *, HOST_WIDE_INT *, HOST_WIDE_INT *);