From patchwork Sat Aug 31 12:44:25 2013 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: Jan Hubicka X-Patchwork-Id: 271526 Return-Path: X-Original-To: incoming@patchwork.ozlabs.org Delivered-To: patchwork-incoming@bilbo.ozlabs.org Received: from sourceware.org (server1.sourceware.org [209.132.180.131]) (using TLSv1 with cipher DHE-RSA-AES256-SHA (256/256 bits)) (Client CN "www.sourceware.org", Issuer "StartCom Class 1 Primary Intermediate Server CA" (not verified)) by ozlabs.org (Postfix) with ESMTPS id 667242C009C for ; Sat, 31 Aug 2013 22:44:40 +1000 (EST) DomainKey-Signature: a=rsa-sha1; c=nofws; d=gcc.gnu.org; h=list-id :list-unsubscribe:list-archive:list-post:list-help:sender:date :from:to:subject:message-id:references:mime-version:content-type :in-reply-to; q=dns; s=default; b=KPcDS3xdMbLZdQv2+Png9d0vzFJb7N iQdlY817PMrn2P1KFlbS6i1R53geEYXPTxJTI7SswT/pHsk68HeooN0x35kOfi4r yAnsBwhK1WTH40JOTIo+qZNKrw0+Io0iEkDbeu0FdgqetuywhfhMq+NI6Tig8KzY 2J+jmHtT743RI= DKIM-Signature: v=1; a=rsa-sha1; c=relaxed; d=gcc.gnu.org; h=list-id :list-unsubscribe:list-archive:list-post:list-help:sender:date :from:to:subject:message-id:references:mime-version:content-type :in-reply-to; s=default; bh=VG7cXC3Kcpy7YgifKKLcr9sYhDY=; b=Subu aJZ4v8um0xwTz1lYlJK7g/25JGX+tz72tcCsUfrkrOn3lZXKHwKfLo89VP9xhd1x HVNsTtj+9FwJOo87aG5W4h+9s9Ng+UFK6gqYKsdKRI8nJC2gZPQyAd+EuI953hWD SO4NosYK+cvlpxWBDnVT0OKmc/KhYI4U9zM65hw= Received: (qmail 10473 invoked by alias); 31 Aug 2013 12:44:32 -0000 Mailing-List: contact gcc-patches-help@gcc.gnu.org; run by ezmlm Precedence: bulk List-Id: List-Unsubscribe: List-Archive: List-Post: List-Help: Sender: gcc-patches-owner@gcc.gnu.org Delivered-To: mailing list gcc-patches@gcc.gnu.org Received: (qmail 10464 invoked by uid 89); 31 Aug 2013 12:44:32 -0000 Received: from nikam.ms.mff.cuni.cz (HELO nikam.ms.mff.cuni.cz) (195.113.20.16) by sourceware.org (qpsmtpd/0.93/v0.84-503-g423c35a) with (AES256-SHA encrypted) ESMTPS; Sat, 31 Aug 2013 12:44:32 +0000 Authentication-Results: sourceware.org; auth=none X-Virus-Found: No X-Spam-SWARE-Status: No, score=-1.7 required=5.0 tests=AWL, BAYES_00, NO_RELAYS autolearn=ham version=3.3.2 X-HELO: nikam.ms.mff.cuni.cz Received: by nikam.ms.mff.cuni.cz (Postfix, from userid 16202) id DB5BE541AC4; Sat, 31 Aug 2013 14:44:25 +0200 (CEST) Date: Sat, 31 Aug 2013 14:44:25 +0200 From: Jan Hubicka To: Jan Hubicka , gcc-patches@gcc.gnu.org Subject: Re: Fix OBJ_TYPE_REF handling in ipa-cp Message-ID: <20130831124425.GB12966@kam.mff.cuni.cz> References: <20130822153350.GD19256@kam.mff.cuni.cz> <20130826212435.GB9816@alvy.suse.cz> MIME-Version: 1.0 Content-Disposition: inline In-Reply-To: <20130826212435.GB9816@alvy.suse.cz> User-Agent: Mutt/1.5.20 (2009-06-14) > > 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. > > Hopefully I'll get rid of the component_types in the jump functions > and most of this won't be necesary. Meanwhile, this is OK. Indeed, I hope these will go. I updated the patch to tree after your changes and fixed the remaining uses of detect_type_change so detect_type_change_1 can go completely. Bootstrapped/regtested x86_64-linux and also tested with Firefox build, comitted. Interestingly, we now have smaller static counts of devirtualization on firefox than two weeks ago. It is not caused by this patch however. While looking for possible causes I also noticed we don't seem to handle invisible references well. Consider: class A {virtual void b(void) { };}; class B : public A {virtual void b(void) { };}; void q (class A a); void qq (class A *a); void t (class A a) { q(a); qq(&a); } void m() { class B b; t(b); } With -O2 -fno-early-inling -flto I get: m() () { struct B b; struct A D.2267; : B::B (&b); A::A (&D.2267, &b.D.2212); t (&D.2267); D.2267 ={v} {CLOBBER}; b ={v} {CLOBBER}; return; } t(A) (struct A & restrict a) { struct A D.2242; : A::A (&D.2242, a_2(D)); q (&D.2242); D.2242 ={v} {CLOBBER}; qq (a_2(D)); return; } I.e. t is called with invisible reference. Now we get: Jump functions: Jump functions of caller m()/12: callsite m()/12 -> t(A)/5 : param 0: UNKNOWN callsite m()/12 -> A::A(A const&)/4 : param 0: KNOWN TYPE: base struct A, offset 0, component struct A param 1: KNOWN TYPE: base struct B, offset 0, component const struct A callsite m()/12 -> B::B()/11 : param 0: KNOWN TYPE: base struct B, offset 0, component struct B Jump functions of caller t(A)/5: callsite t(A)/5 -> qq(A*)/20 : param 0: PASS THROUGH: 0, op nop_expr, type_preserved callsite t(A)/5 -> q(A)/19 : param 0: UNKNOWN callsite t(A)/5 -> A::A(A const&)/4 : param 0: KNOWN TYPE: base struct A, offset 0, component struct A param 1: PASS THROUGH: 0, op nop_expr, type_preserved I think m()->t() has no type and t->qq is pass thorugh. So we miss the fact that t->qq is known type of A. Do we need jump function that is PASS THROGH & KNOWN_TYPE at once? Honza * ipa-prop.c (ipa_set_jf_known_type): Check that we add only records. (detect_type_change_1): Rename to ... (detect_type_change): ... this one; early return on non-polymorphic types. (detect_type_change_ssa): Add comp_type parameter; update use of detect_type_change. (compute_complex_assign_jump_func): Add param_type parameter; update use of detect_type_change_ssa. (compute_complex_ancestor_jump_func): Likewise. (ipa_get_callee_param_type): New function. (ipa_compute_jump_functions_for_edge): Compute parameter type; update calls to the jump function computation functions. Index: ipa-prop.c =================================================================== --- ipa-prop.c (revision 202092) +++ ipa-prop.c (working copy) @@ -371,6 +371,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; @@ -633,13 +635,16 @@ check_stmt_for_type_change (ao_ref *ao A -/* Like detect_type_change but with extra argument COMP_TYPE which will become - the component type part of new JFUNC of dynamic type change is detected and - the new base type is identified. */ +/* Detect whether the dynamic type of ARG of COMP_TYPE has changed (before + callsite CALL) by looking for assignments to its virtual table pointer. If + it is, return true and fill in the jump function JFUNC with relevant type + information or set it to unknown. ARG is the object itself (not a pointer + to it, unless dereferenced). BASE is the base of the memory access as + returned by get_ref_base_and_extent, as is the offset. */ static bool -detect_type_change_1 (tree arg, tree base, tree comp_type, gimple call, - struct ipa_jump_func *jfunc, HOST_WIDE_INT offset) +detect_type_change (tree arg, tree base, tree comp_type, gimple call, + struct ipa_jump_func *jfunc, HOST_WIDE_INT offset) { struct type_change_info tci; ao_ref ao; @@ -649,7 +654,12 @@ detect_type_change_1 (tree arg, tree bas || handled_component_p (arg)); /* Const calls cannot call virtual methods through VMT and so type changes do not matter. */ - if (!flag_devirtualize || !gimple_vuse (call)) + if (!flag_devirtualize || !gimple_vuse (call) + /* Be sure expected_type is polymorphic. */ + || !comp_type + || TREE_CODE (comp_type) != RECORD_TYPE + || !TYPE_BINFO (comp_type) + || !BINFO_VTABLE (TYPE_BINFO (comp_type))) return false; ao_ref_init (&ao, arg); @@ -679,40 +689,23 @@ detect_type_change_1 (tree arg, tree bas return true; } -/* Detect whether the dynamic type of ARG has changed (before callsite CALL) by - looking for assignments to its virtual table pointer. If it is, return true - and fill in the jump function JFUNC with relevant type information or set it - to unknown. ARG is the object itself (not a pointer to it, unless - dereferenced). BASE is the base of the memory access as returned by - get_ref_base_and_extent, as is the offset. */ - -static bool -detect_type_change (tree arg, tree base, gimple call, - struct ipa_jump_func *jfunc, HOST_WIDE_INT offset) -{ - return detect_type_change_1 (arg, base, TREE_TYPE (arg), call, jfunc, offset); -} - /* 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). */ 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) + || !POINTER_TYPE_P (TREE_TYPE (arg))) return false; - comp_type = TREE_TYPE (TREE_TYPE (arg)); arg = build2 (MEM_REF, ptr_type_node, arg, build_int_cst (ptr_type_node, 0)); - return detect_type_change_1 (arg, arg, comp_type, call, jfunc, 0); + return detect_type_change (arg, arg, comp_type, call, jfunc, 0); } /* Callback of walk_aliased_vdefs. Flags that it has been invoked to the @@ -988,7 +981,8 @@ 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; @@ -1030,7 +1024,11 @@ compute_complex_assign_jump_func (struct { bool agg_p = parm_ref_data_pass_through_p (&parms_ainfo[index], call, tc_ssa); - bool type_p = !detect_type_change_ssa (tc_ssa, call, jfunc); + bool type_p = false; + + if (param_type && POINTER_TYPE_P (param_type)) + type_p = !detect_type_change_ssa (tc_ssa, TREE_TYPE (param_type), + call, jfunc); if (type_p || jfunc->type == IPA_JF_UNKNOWN) ipa_set_jf_simple_pass_through (jfunc, index, agg_p, type_p); } @@ -1057,9 +1055,10 @@ compute_complex_assign_jump_func (struct /* Dynamic types are changed in constructors and destructors. */ index = ipa_get_param_decl_index (info, SSA_NAME_VAR (ssa)); - if (index >= 0) + if (index >= 0 && param_type && POINTER_TYPE_P (param_type)) { - bool type_p = !detect_type_change (op1, base, call, jfunc, offset); + bool type_p = !detect_type_change (op1, base, TREE_TYPE (param_type), + call, jfunc, offset); if (type_p || jfunc->type == IPA_JF_UNKNOWN) ipa_set_ancestor_jf (jfunc, offset, TREE_TYPE (op1), index, parm_ref_data_pass_through_p (&parms_ainfo[index], @@ -1137,7 +1136,7 @@ static void compute_complex_ancestor_jump_func (struct ipa_node_params *info, struct param_analysis_info *parms_ainfo, struct ipa_jump_func *jfunc, - gimple call, gimple phi) + gimple call, gimple phi, tree param_type) { HOST_WIDE_INT offset; gimple assign, cond; @@ -1188,7 +1187,10 @@ compute_complex_ancestor_jump_func (stru return; } - bool type_p = !detect_type_change (obj, expr, call, jfunc, offset); + bool type_p = false; + if (param_type && POINTER_TYPE_P (param_type)) + type_p = !detect_type_change (obj, expr, TREE_TYPE (param_type), + call, jfunc, offset); if (type_p || jfunc->type == IPA_JF_UNKNOWN) ipa_set_ancestor_jf (jfunc, offset, TREE_TYPE (obj), index, parm_ref_data_pass_through_p (&parms_ainfo[index], @@ -1197,18 +1199,24 @@ 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 + /* Be sure expected_type is polymorphic. */ + || !expected_type + || TREE_CODE (expected_type) != RECORD_TYPE + || !TYPE_BINFO (expected_type) + || !BINFO_VTABLE (TYPE_BINFO (expected_type))) return; op = TREE_OPERAND (op, 0); @@ -1220,11 +1228,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 (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 @@ -1495,6 +1503,37 @@ determine_known_aggregate_parts (gimple } } +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. */ @@ -1519,6 +1558,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); @@ -1547,9 +1587,14 @@ ipa_compute_jump_functions_for_edge (str bool agg_p, type_p; agg_p = parm_ref_data_pass_through_p (&parms_ainfo[index], call, arg); - type_p = !detect_type_change_ssa (arg, call, jfunc); + if (param_type && POINTER_TYPE_P (param_type)) + type_p = !detect_type_change_ssa (arg, TREE_TYPE (param_type), + call, jfunc); + else + type_p = false; if (type_p || jfunc->type == IPA_JF_UNKNOWN) - ipa_set_jf_simple_pass_through (jfunc, index, agg_p, type_p); + ipa_set_jf_simple_pass_through (jfunc, index, agg_p, + type_p); } } else @@ -1557,14 +1602,18 @@ 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); + call, stmt, param_type); } } else - compute_known_type_jump_func (arg, jfunc, call); + compute_known_type_jump_func (arg, jfunc, call, + param_type + && POINTER_TYPE_P (param_type) + ? TREE_TYPE (param_type) + : NULL); if ((jfunc->type != IPA_JF_PASS_THROUGH || !ipa_get_jf_pass_through_agg_preserved (jfunc)) @@ -1908,7 +1957,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 @@ -1922,7 +1972,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 (obj, expr, obj_type_ref_class (target), + call, &jfunc, anc_offset)) return; } @@ -2134,7 +2185,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);