From patchwork Mon Sep 20 13:50:17 2010 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: Jan Hubicka X-Patchwork-Id: 65210 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]) by ozlabs.org (Postfix) with SMTP id 7EAE2B6ED0 for ; Mon, 20 Sep 2010 23:50:38 +1000 (EST) Received: (qmail 32163 invoked by alias); 20 Sep 2010 13:50:35 -0000 Received: (qmail 32121 invoked by uid 22791); 20 Sep 2010 13:50:31 -0000 X-SWARE-Spam-Status: No, hits=-1.7 required=5.0 tests=AWL, BAYES_00, TW_TM, T_RP_MATCHES_RCVD X-Spam-Check-By: sourceware.org Received: from nikam-dmz.ms.mff.cuni.cz (HELO nikam.ms.mff.cuni.cz) (195.113.20.16) by sourceware.org (qpsmtpd/0.43rc1) with ESMTP; Mon, 20 Sep 2010 13:50:21 +0000 Received: from localhost (occam.ms.mff.cuni.cz [195.113.18.121]) by nikam.ms.mff.cuni.cz (Postfix) with ESMTP id DB9499ACB46; Mon, 20 Sep 2010 15:50:17 +0200 (CEST) Received: by localhost (Postfix, from userid 16202) id D58B75641B5; Mon, 20 Sep 2010 15:50:17 +0200 (CEST) Date: Mon, 20 Sep 2010 15:50:17 +0200 From: Jan Hubicka To: Jan Hubicka Cc: gcc-patches@gcc.gnu.org, rguenther@suse.de Subject: Re: PR tree-optimization/45605 Message-ID: <20100920135017.GB28003@kam.mff.cuni.cz> References: <20100916234812.GE6006@kam.mff.cuni.cz> <20100917160337.GG4049@virgil.arch.suse.de> <20100918234028.GM22498@kam.mff.cuni.cz> <20100918234340.GN22498@kam.mff.cuni.cz> MIME-Version: 1.0 Content-Disposition: inline In-Reply-To: <20100918234340.GN22498@kam.mff.cuni.cz> User-Agent: Mutt/1.5.18 (2008-05-17) 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 Hi, I've tested the other part of previous patch and comitted everything except for the code introducing folding itself as they address other latent issues. The problem with folders being called before cgraph&varpool are built is common to issue I was addressing by my earlier string_constant patch that was refused as too confusing. Constant constructors are just special case of wider issue that with linker plugin or WHOPR we do have more knowledge about what is locally bound than in normal compilation. After discussion with Richard on IRC, we got to conclusion that to address the issue we probably should store resolution decisions into varpool and cgraph nodes. Varpool's const_value_known and cgraph+varpool used_in_object_file flags can then be turned into predicates looking into resolutions and DECL flags. Also binds_local_p can be strenghtened to look up resolution info and take it into account when dealing with weak, external and comdat decls. I have patch for this change, but since it is tricky by itself (updates binds_local_p logic, adds logic into lto-symtab to bookkeep what values come from linker and what was decided in GCC, etc.) I decided to break those changes. This is patch that goes half way by introducing const_value_known_p predicate while keeping current way of passing const_value_known flag from WPA to LTRANS. I updated the predicate to work on CONST_DECL, automatic vars, other decls and vars w/o varpool entries allocated (yet), so it can be used more conveniently. Now when one has non function/method DECL, it is possible use this predicate to test whether it makes sense to look at DECL_INITIAL to get the constructor. One no longer needs to special case constant pool, CONST_DECL, and check that variable is static before attempting to do so. This finally lets us to do the statement folding during gimplification without ICEs. Bootstrapped/regtested x86_64-linux, OK? Honza * cgraph.h (const_value_known_p): Declare. (varpool_decide_const_value_known): Remove. * tree-ssa-ccp.c (get_base_constructor): Use it. * lto-cgraph.c (compute_ltrans_boundary): Likewise. * expr.c (string_constant): Likewise. * tree-ssa-loop-ivcanon.c (constant_after_peeling): Likewise. * ipa.c (ipa_discover_readonly_nonaddressable_var, function_and_variable_visibility): Likewise. * gimplify.c (gimplify_call_expr): Likewise. * gimple-fold.c (get_symbol_constant_value): Likewise. * varpool.c (varpool_decide_const_value_known): Replace by... (const_value_known_p): ... this one; handle other kinds of DECLs too and work for automatic vars. (varpool_finalize_decl): Use const_value_known_p. * lto.c (lto_promote_cross_file_statics): Use const_value_known_p. * g++.dg/tree-ssa/pr45605.C: New testcase. Index: cgraph.h =================================================================== --- cgraph.h (revision 164400) +++ cgraph.h (working copy) @@ -728,7 +728,7 @@ void varpool_empty_needed_queue (void); bool varpool_extra_name_alias (tree, tree); const char * varpool_node_name (struct varpool_node *node); void varpool_reset_queue (void); -bool varpool_decide_const_value_known (struct varpool_node *node); +bool const_value_known_p (tree); /* Walk all reachable static variables. */ #define FOR_EACH_STATIC_VARIABLE(node) \ Index: testsuite/g++.dg/tree-ssa/pr45605.C =================================================================== --- testsuite/g++.dg/tree-ssa/pr45605.C (revision 0) +++ testsuite/g++.dg/tree-ssa/pr45605.C (revision 0) @@ -0,0 +1,37 @@ +/* { dg-do compile } */ +/* { dg-options "-O1 -fdump-tree-ssa" } */ +extern "C" void abort(); +bool destructor_called = false; + +struct B { + virtual void Run(){}; +}; + +struct D : public B { + virtual void Run() + { + struct O { + ~O() { destructor_called = true; }; + } o; + + struct Raiser { + Raiser() throw( int ) {throw 1;}; + } raiser; + }; +}; + +int main() { + try { + D d; + static_cast(d).Run(); + } catch (...) {} + + if (!destructor_called) + abort (); +} + + + +/* We should devirtualize call to D::Run */ +/* { dg-final { scan-tree-dump-times "D::Run (" 1 "ssa"} } */ +/* { dg-final { cleanup-tree-dump "ssa" } } */ Index: tree-ssa-ccp.c =================================================================== --- tree-ssa-ccp.c (revision 164400) +++ tree-ssa-ccp.c (working copy) @@ -1342,9 +1342,7 @@ get_base_constructor (tree base, tree *o switch (TREE_CODE (base)) { case VAR_DECL: - if (!TREE_READONLY (base) - || ((TREE_STATIC (base) || DECL_EXTERNAL (base)) - && !varpool_get_node (base)->const_value_known)) + if (!const_value_known_p (base)) return NULL_TREE; /* Fallthru. */ Index: lto-cgraph.c =================================================================== --- lto-cgraph.c (revision 164400) +++ lto-cgraph.c (working copy) @@ -813,8 +813,7 @@ compute_ltrans_boundary (struct lto_out_ if (DECL_INITIAL (vnode->decl) && !lto_varpool_encoder_encode_initializer_p (varpool_encoder, vnode) - && (DECL_IN_CONSTANT_POOL (vnode->decl) - || vnode->const_value_known)) + && const_value_known_p (vnode->decl)) { lto_set_varpool_encoder_encode_initializer (varpool_encoder, vnode); add_references (encoder, varpool_encoder, &vnode->ref_list); Index: expr.c =================================================================== --- expr.c (revision 164400) +++ expr.c (working copy) @@ -9851,16 +9851,10 @@ string_constant (tree arg, tree *ptr_off int length; /* Variables initialized to string literals can be handled too. */ - if (DECL_INITIAL (array) == NULL_TREE + if (!const_value_known_p (array) || TREE_CODE (DECL_INITIAL (array)) != STRING_CST) return 0; - /* If they are read-only, non-volatile and bind locally. */ - if (! TREE_READONLY (array) - || TREE_SIDE_EFFECTS (array) - || ! targetm.binds_local_p (array)) - return 0; - /* Avoid const char foo[4] = "abcde"; */ if (DECL_SIZE_UNIT (array) == NULL_TREE || TREE_CODE (DECL_SIZE_UNIT (array)) != INTEGER_CST Index: tree-ssa-loop-ivcanon.c =================================================================== --- tree-ssa-loop-ivcanon.c (revision 164400) +++ tree-ssa-loop-ivcanon.c (working copy) @@ -162,10 +162,8 @@ constant_after_peeling (tree op, gimple /* First make fast look if we see constant array inside. */ while (handled_component_p (base)) base = TREE_OPERAND (base, 0); - if ((DECL_P (base) - && TREE_STATIC (base) - && TREE_READONLY (base) - && varpool_get_node (base)->const_value_known) + if ((DECL_P (base) == VAR_DECL + && const_value_known_p (base)) || CONSTANT_CLASS_P (base)) { /* If so, see if we understand all the indices. */ Index: ipa.c =================================================================== --- ipa.c (revision 164400) +++ ipa.c (working copy) @@ -565,7 +565,7 @@ ipa_discover_readonly_nonaddressable_var if (dump_file) fprintf (dump_file, " %s (read-only)", varpool_node_name (vnode)); TREE_READONLY (vnode->decl) = 1; - vnode->const_value_known |= varpool_decide_const_value_known (vnode); + vnode->const_value_known |= const_value_known_p (vnode->decl); } } if (dump_file) @@ -774,7 +774,7 @@ function_and_variable_visibility (bool w DECL_COMMON (vnode->decl) = 0; /* Even extern variables might have initializers known. See, for example testsuite/g++.dg/opt/static3.C */ - vnode->const_value_known |= varpool_decide_const_value_known (vnode); + vnode->const_value_known |= const_value_known_p (vnode->decl); } for (vnode = varpool_nodes_queue; vnode; vnode = vnode->next_needed) { @@ -809,7 +809,7 @@ function_and_variable_visibility (bool w gcc_assert (in_lto_p || whole_program || !TREE_PUBLIC (vnode->decl)); cgraph_make_decl_local (vnode->decl); } - vnode->const_value_known |= varpool_decide_const_value_known (vnode); + vnode->const_value_known |= const_value_known_p (vnode->decl); gcc_assert (TREE_STATIC (vnode->decl)); } pointer_set_destroy (aliased_nodes); Index: gimplify.c =================================================================== --- gimplify.c (revision 164400) +++ gimplify.c (working copy) @@ -2479,8 +2479,11 @@ gimplify_call_expr (tree *expr_p, gimple { /* The CALL_EXPR in *EXPR_P is already in GIMPLE form, so all we have to do is replicate it as a GIMPLE_CALL tuple. */ + gimple_stmt_iterator gsi; call = gimple_build_call_from_tree (*expr_p); gimplify_seq_add_stmt (pre_p, call); + gsi = gsi_last (*pre_p); + fold_stmt (&gsi); *expr_p = NULL_TREE; } Index: gimple-fold.c =================================================================== --- gimple-fold.c (revision 164402) +++ gimple-fold.c (working copy) @@ -122,9 +122,7 @@ canonicalize_constructor_val (tree cval) tree get_symbol_constant_value (tree sym) { - if ((TREE_STATIC (sym) || DECL_EXTERNAL (sym)) - && (TREE_CODE (sym) == CONST_DECL - || varpool_get_node (sym)->const_value_known)) + if (const_value_known_p (sym)) { tree val = DECL_INITIAL (sym); if (val) Index: lto/lto.c =================================================================== --- lto/lto.c (revision 164400) +++ lto/lto.c (working copy) @@ -1008,7 +1008,7 @@ lto_promote_cross_file_statics (void) from this partition that are not in this partition. This needs to be done recursively. */ for (vnode = varpool_nodes; vnode; vnode = vnode->next) - if ((vnode->const_value_known || DECL_IN_CONSTANT_POOL (vnode->decl)) + if (const_value_known_p (vnode->decl) && DECL_INITIAL (vnode->decl) && !varpool_node_in_set_p (vnode, vset) && referenced_from_this_partition_p (&vnode->ref_list, set, vset) Index: varpool.c =================================================================== --- varpool.c (revision 164400) +++ varpool.c (working copy) @@ -359,21 +359,42 @@ decide_is_variable_needed (struct varpoo return true; } -/* Return if NODE is constant and its initial value is known (so we can do - constant folding). The decision depends on whole program decisions - and can not be recomputed at ltrans stage for variables from other - partitions. For this reason the new value should be always combined - with the previous knowledge. */ +/* Return if DECL is constant and its initial value is known (so we can do + constant folding using DECL_INITIAL (decl)). */ bool -varpool_decide_const_value_known (struct varpool_node *node) +const_value_known_p (tree decl) { - tree decl = node->decl; + struct varpool_node *vnode; + + if (TREE_CODE (decl) == PARM_DECL + || TREE_CODE (decl) == RESULT_DECL) + return false; + + if (TREE_CODE (decl) == CONST_DECL + || DECL_IN_CONSTANT_POOL (decl)) + return true; - gcc_assert (TREE_STATIC (decl) || DECL_EXTERNAL (decl)); gcc_assert (TREE_CODE (decl) == VAR_DECL); + if (!TREE_READONLY (decl)) return false; + + /* Gimplifier takes away constructors of local vars */ + if (!TREE_STATIC (decl) && !DECL_EXTERNAL (decl)) + return DECL_INITIAL (decl) != NULL; + + gcc_assert (TREE_STATIC (decl) || DECL_EXTERNAL (decl)); + + /* In WHOPR mode we can put variable into one partition + and make it external in the other partition. In this + case we still know the value, but it can't be determined + from DECL flags. For this reason we keep const_value_known + flag in varpool nodes. */ + if ((vnode = varpool_get_node (decl)) + && vnode->const_value_known) + return true; + /* Variables declared 'const' without an initializer have zero as the initializer if they may not be overridden at link or run time. */ @@ -423,7 +444,7 @@ varpool_finalize_decl (tree decl) there. */ else if (TREE_PUBLIC (decl) && !DECL_COMDAT (decl) && !DECL_EXTERNAL (decl)) varpool_mark_needed_node (node); - node->const_value_known |= varpool_decide_const_value_known (node); + node->const_value_known |= const_value_known_p (node->decl); if (cgraph_global_info_ready) varpool_assemble_pending_decls (); }