Hi, this problem was noticed by my verifier that binfo walks are not across type hiearchy. ipa_intraprocedural_devirtualization is one remaining place where we take class of object from OBJ_TYPE_REF_OBJECT instead of obj_type_ref_class_type.
Unforutnately I noticed that this problem is propagated quite further across ipa-prop design. We assume that types of pointers taken from gimple call arguments are types of pointers to classes pass down to the callee. This is not true after propagation. I did not fix the all places, only places needed to get parameter for ipa_set_jf_known_type and detect_type_change_ssa right. Also I modified ipa_set_jf_known_type to not record non-polymorphic type. It is a waste of memory and LTO streaming bandwidth. Bootstrapped/regtesed x86_64-linux. Martin, please can you review the change? * ipa-prop.c (ipa_set_jf_known_type): Check that component type is a record type with BINFO. (detect_type_change_ssa): Add comp_type argument. (compute_complex_assign_jump_func): Add param_type argument; pass it down to detect_type_change_ssa. (compute_known_type_jump_func): Add expected_type parameter. Do not bother tracking a non-polymorphic type. (ipa_get_callee_param_type): New function. (ipa_compute_jump_functions_for_edge): Pass down calle parm types. (ipa_analyze_virtual_call_uses): Use class typee as argument of detect_type_change_1. (ipa_intraprocedural_devirtualization): Pass down class type. Index: ipa-prop.c =================================================================== --- ipa-prop.c (revision 201919) +++ ipa-prop.c (working copy) @@ -367,6 +367,8 @@ static void ipa_set_jf_known_type (struct ipa_jump_func *jfunc, HOST_WIDE_INT offset, tree base_type, tree component_type) { + gcc_assert (TREE_CODE (component_type) == RECORD_TYPE + && TYPE_BINFO (component_type)); jfunc->type = IPA_JF_KNOWN_TYPE; jfunc->value.known_type.offset = offset, jfunc->value.known_type.base_type = base_type; @@ -674,20 +676,18 @@ detect_type_change (tree arg, tree base, /* Like detect_type_change but ARG is supposed to be a non-dereferenced pointer SSA name (its dereference will become the base and the offset is assumed to - be zero). */ + be zero). COMP_TYPE is type of object being tracked. */ static bool -detect_type_change_ssa (tree arg, gimple call, struct ipa_jump_func *jfunc) +detect_type_change_ssa (tree arg, tree comp_type, + gimple call, struct ipa_jump_func *jfunc) { - tree comp_type; - gcc_checking_assert (TREE_CODE (arg) == SSA_NAME); if (!flag_devirtualize || !POINTER_TYPE_P (TREE_TYPE (arg)) || TREE_CODE (TREE_TYPE (TREE_TYPE (arg))) != RECORD_TYPE) return false; - comp_type = TREE_TYPE (TREE_TYPE (arg)); arg = build2 (MEM_REF, ptr_type_node, arg, build_int_cst (ptr_type_node, 0)); @@ -961,13 +961,16 @@ ipa_load_from_parm_agg (struct ipa_node_ INFO is the structure describing individual parameters access different stages of IPA optimizations. PARMS_AINFO contains the information that is - only needed for intraprocedural analysis. */ + only needed for intraprocedural analysis. + + PARAM_TYPE is type of the parameter, NULL if not available. */ static void compute_complex_assign_jump_func (struct ipa_node_params *info, struct param_analysis_info *parms_ainfo, struct ipa_jump_func *jfunc, - gimple call, gimple stmt, tree name) + gimple call, gimple stmt, tree name, + tree param_type) { HOST_WIDE_INT offset, size, max_size; tree op1, tc_ssa, base, ssa; @@ -1006,7 +1009,10 @@ compute_complex_assign_jump_func (struct gimple_assign_rhs_code (stmt)); } else if (gimple_assign_single_p (stmt) - && !detect_type_change_ssa (tc_ssa, call, jfunc)) + && param_type + && !detect_type_change_ssa (tc_ssa, + TREE_TYPE (param_type), + call, jfunc)) { bool agg_p = parm_ref_data_pass_through_p (&parms_ainfo[index], call, tc_ssa); @@ -1171,18 +1177,25 @@ compute_complex_ancestor_jump_func (stru /* Given OP which is passed as an actual argument to a called function, determine if it is possible to construct a KNOWN_TYPE jump function for it - and if so, create one and store it to JFUNC. */ + and if so, create one and store it to JFUNC. + EXPECTED_TYPE represents a type the argument should be in */ static void compute_known_type_jump_func (tree op, struct ipa_jump_func *jfunc, - gimple call) + gimple call, tree expected_type) { HOST_WIDE_INT offset, size, max_size; tree base; if (!flag_devirtualize || TREE_CODE (op) != ADDR_EXPR - || TREE_CODE (TREE_TYPE (TREE_TYPE (op))) != RECORD_TYPE) + || TREE_CODE (TREE_TYPE (TREE_TYPE (op))) != RECORD_TYPE + /* Do not bother to track types that are not polymorphic. + We use type knowledge only for devirtualization. */ + || !expected_type + || TREE_CODE (expected_type) != RECORD_TYPE + || !TYPE_BINFO (expected_type) + || !BINFO_VTABLE (TYPE_BINFO (expected_type))) return; op = TREE_OPERAND (op, 0); @@ -1194,11 +1207,11 @@ compute_known_type_jump_func (tree op, s || is_global_var (base)) return; - if (!TYPE_BINFO (TREE_TYPE (base)) - || detect_type_change (op, base, call, jfunc, offset)) + if (detect_type_change_1 (op, base, expected_type, call, jfunc, offset)) return; - ipa_set_jf_known_type (jfunc, offset, TREE_TYPE (base), TREE_TYPE (op)); + ipa_set_jf_known_type (jfunc, offset, TREE_TYPE (base), + expected_type); } /* Inspect the given TYPE and return true iff it has the same structure (the @@ -1469,6 +1482,42 @@ determine_known_aggregate_parts (gimple } } +/* Return type of I-th parameter of callee of E. This may differ from + type of I-th argument of call operand of E->call_stmt because + pointer conversions are considered useless. For devirtualization + we really need the type of object being passed. */ + +static tree +ipa_get_callee_param_type (struct cgraph_edge *e, int i) +{ + int n; + tree type = (e->callee + ? TREE_TYPE (e->callee->symbol.decl) + : gimple_call_fntype (e->call_stmt)); + tree t = TYPE_ARG_TYPES (type); + + for (n = 0; n < i; n++) + { + if (!t) + break; + t = TREE_CHAIN (t); + } + if (t) + return TREE_VALUE (t); + if (!e->callee) + return NULL; + t = DECL_ARGUMENTS (e->callee->symbol.decl); + for (n = 0; n < i; n++) + { + if (!t) + return NULL; + t = TREE_CHAIN (t); + } + if (t) + return TREE_TYPE (t); + return NULL; +} + /* Compute jump function for all arguments of callsite CS and insert the information in the jump_functions array in the ipa_edge_args corresponding to this callsite. */ @@ -1493,6 +1542,7 @@ ipa_compute_jump_functions_for_edge (str { struct ipa_jump_func *jfunc = ipa_get_ith_jump_func (args, n); tree arg = gimple_call_arg (call, n); + tree param_type = ipa_get_callee_param_type (cs, n); if (is_gimple_ip_invariant (arg)) ipa_set_jf_constant (jfunc, arg, cs); @@ -1517,7 +1567,8 @@ ipa_compute_jump_functions_for_edge (str { int index = ipa_get_param_decl_index (info, SSA_NAME_VAR (arg)); if (index >= 0 - && !detect_type_change_ssa (arg, call, jfunc)) + && !detect_type_change_ssa (arg, TREE_TYPE (TREE_TYPE (arg)), + call, jfunc)) { bool agg_p; agg_p = parm_ref_data_pass_through_p (&parms_ainfo[index], @@ -1530,14 +1581,17 @@ ipa_compute_jump_functions_for_edge (str gimple stmt = SSA_NAME_DEF_STMT (arg); if (is_gimple_assign (stmt)) compute_complex_assign_jump_func (info, parms_ainfo, jfunc, - call, stmt, arg); + call, stmt, arg, param_type); else if (gimple_code (stmt) == GIMPLE_PHI) compute_complex_ancestor_jump_func (info, parms_ainfo, jfunc, call, stmt); } } else - compute_known_type_jump_func (arg, jfunc, call); + compute_known_type_jump_func (arg, jfunc, call, + param_type + ? TREE_TYPE (param_type) + : NULL); if ((jfunc->type != IPA_JF_PASS_THROUGH || !ipa_get_jf_pass_through_agg_preserved (jfunc)) @@ -1881,7 +1935,8 @@ ipa_analyze_virtual_call_uses (struct cg anc_offset = 0; index = ipa_get_param_decl_index (info, SSA_NAME_VAR (obj)); gcc_assert (index >= 0); - if (detect_type_change_ssa (obj, call, &jfunc)) + if (detect_type_change_ssa (obj, obj_type_ref_class (target), + call, &jfunc)) return; } else @@ -1895,7 +1950,8 @@ ipa_analyze_virtual_call_uses (struct cg index = ipa_get_param_decl_index (info, SSA_NAME_VAR (TREE_OPERAND (expr, 0))); gcc_assert (index >= 0); - if (detect_type_change (obj, expr, call, &jfunc, anc_offset)) + if (detect_type_change_1 (obj, expr, obj_type_ref_class (target), + call, &jfunc, anc_offset)) return; } @@ -2107,7 +2163,7 @@ ipa_intraprocedural_devirtualization (gi jfunc.type = IPA_JF_UNKNOWN; compute_known_type_jump_func (OBJ_TYPE_REF_OBJECT (otr), &jfunc, - call); + call, obj_type_ref_class (otr)); if (jfunc.type != IPA_JF_KNOWN_TYPE) return NULL_TREE; binfo = ipa_binfo_from_known_type_jfunc (&jfunc);