From patchwork Wed Oct 9 15:37:02 2013 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: Andrew MacLeod X-Patchwork-Id: 281922 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 did not present a certificate) by ozlabs.org (Postfix) with ESMTPS id D50022C0109 for ; Thu, 10 Oct 2013 02:37:14 +1100 (EST) DomainKey-Signature: a=rsa-sha1; c=nofws; d=gcc.gnu.org; h=list-id :list-unsubscribe:list-archive:list-post:list-help:sender :message-id:date:from:mime-version:to:cc:subject:references :in-reply-to:content-type; q=dns; s=default; b=tam9PfchkjbCIjORs br+8c1YMyeLhagqC2l0FE7X1zTj7txgIOX5POpgkFB7/THQxpV9BLzAAETyS5EfQ bYsk5Vsm2fzwkaPJVha8s0AnZpjtyEnE2PhdJ8iF7X5nlLAzb0cengVCBVt2URbx yQXxV5Y5e6x0TRayH9ZbJHqxyg= 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 :message-id:date:from:mime-version:to:cc:subject:references :in-reply-to:content-type; s=default; bh=BySYEswSifKRkg7vaTyyBIb Ie9g=; b=D1Ot248wDUu6mHua+n+0eqKa1EJm1pmno4TThEtohshwvTvjFK/af/W 6IxaKZLjhxO+ec0VCxpFhHnusZTauIsDPlLCoiKxARpsb1ZflLpT7N+O3VumiDwk tsTAglyAGyzByDf5axtodaIa/8pX7S9WgKaQPJHpebv+bFGV7Heo= Received: (qmail 29095 invoked by alias); 9 Oct 2013 15:37:07 -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 29086 invoked by uid 89); 9 Oct 2013 15:37:07 -0000 Authentication-Results: sourceware.org; auth=none X-Virus-Found: No X-Spam-SWARE-Status: No, score=-3.9 required=5.0 tests=AWL, BAYES_00, RP_MATCHES_RCVD, SPF_HELO_PASS, SPF_PASS autolearn=ham version=3.3.2 X-HELO: mx1.redhat.com Received: from mx1.redhat.com (HELO mx1.redhat.com) (209.132.183.28) by sourceware.org (qpsmtpd/0.93/v0.84-503-g423c35a) with ESMTP; Wed, 09 Oct 2013 15:37:06 +0000 Received: from int-mx10.intmail.prod.int.phx2.redhat.com (int-mx10.intmail.prod.int.phx2.redhat.com [10.5.11.23]) by mx1.redhat.com (8.14.4/8.14.4) with ESMTP id r99Fb4qO022313 (version=TLSv1/SSLv3 cipher=DHE-RSA-AES256-SHA bits=256 verify=OK); Wed, 9 Oct 2013 11:37:04 -0400 Received: from [10.10.52.145] (vpn-52-145.rdu2.redhat.com [10.10.52.145]) by int-mx10.intmail.prod.int.phx2.redhat.com (8.14.4/8.14.4) with ESMTP id r99Fb2bc015042; Wed, 9 Oct 2013 11:37:03 -0400 Message-ID: <5255781E.9030700@redhat.com> Date: Wed, 09 Oct 2013 11:37:02 -0400 From: Andrew MacLeod User-Agent: Mozilla/5.0 (X11; Linux x86_64; rv:17.0) Gecko/20130805 Thunderbird/17.0.8 MIME-Version: 1.0 To: Richard Biener CC: gcc-patches , Diego Novillo Subject: Re: [patch] The remainder of tree-flow.h refactored. References: <524EF235.5080803@redhat.com> In-Reply-To: X-IsSubscribed: yes On 10/08/2013 06:22 AM, Richard Biener wrote: > > unvisit_body isn't generic enough to warrant moving out of gimplify.c > (the only user). Bah, now I remember.. so there *are* other users.. this routine is called from various front ends.. fortran, c-family and cp all call it. That is why I wanted to move it to tree.[ch]. it doesn't belong in a gimple file.. it operates on trees and is also used by tree front ends. which then brings with it all the related routines... unshare_body is then exported from tree.c in order for gimplify.c to utilize it. This patch handles just this part. bootstraps on x86_64-unknown-linux-gnu, regressions test are still running. OK? Andrew * tree.h: Adjust prototypes. * gimplify.c (mostly_copy_tree_r, copy_if_shared_r, copy_if_shared, unshare_body, unshare_expr, prune_expr_location, unshare_expr_without_location): Move to tree.c. * tree.c (mostly_copy_tree_r, copy_if_shared_r, copy_if_shared, unshare_body, unshare_expr, prune_expr_location, unshare_expr_without_location): Relocate from gimplify.c. Index: tree.h =================================================================== *** tree.h (revision 203320) --- tree.h (working copy) *************** extern void cache_integer_cst (tree); *** 4203,4212 **** /* In cgraph.c */ extern void change_decl_assembler_name (tree, tree); - /* In gimplify.c */ - extern tree unshare_expr (tree); - extern tree unshare_expr_without_location (tree); - /* In stmt.c */ extern void expand_label (tree); --- 4203,4208 ---- *************** extern bool type_in_anonymous_namespace_ *** 4524,4529 **** --- 4520,4528 ---- extern bool block_may_fallthru (const_tree); extern void using_eh_for_cleanups (void); extern bool using_eh_for_cleanups_p (void); + extern void unshare_body (tree); + extern tree unshare_expr (tree); + extern tree unshare_expr_without_location (tree); /* In tree-nested.c */ extern tree build_addr (tree, tree); Index: gimplify.c =================================================================== *** gimplify.c (revision 203319) --- gimplify.c (working copy) *************** annotate_all_with_location (gimple_seq s *** 813,970 **** } } - /* This page contains routines to unshare tree nodes, i.e. to duplicate tree - nodes that are referenced more than once in GENERIC functions. This is - necessary because gimplification (translation into GIMPLE) is performed - by modifying tree nodes in-place, so gimplication of a shared node in a - first context could generate an invalid GIMPLE form in a second context. - - This is achieved with a simple mark/copy/unmark algorithm that walks the - GENERIC representation top-down, marks nodes with TREE_VISITED the first - time it encounters them, duplicates them if they already have TREE_VISITED - set, and finally removes the TREE_VISITED marks it has set. - - The algorithm works only at the function level, i.e. it generates a GENERIC - representation of a function with no nodes shared within the function when - passed a GENERIC function (except for nodes that are allowed to be shared). - - At the global level, it is also necessary to unshare tree nodes that are - referenced in more than one function, for the same aforementioned reason. - This requires some cooperation from the front-end. There are 2 strategies: - - 1. Manual unsharing. The front-end needs to call unshare_expr on every - expression that might end up being shared across functions. - - 2. Deep unsharing. This is an extension of regular unsharing. Instead - of calling unshare_expr on expressions that might be shared across - functions, the front-end pre-marks them with TREE_VISITED. This will - ensure that they are unshared on the first reference within functions - when the regular unsharing algorithm runs. The counterpart is that - this algorithm must look deeper than for manual unsharing, which is - specified by LANG_HOOKS_DEEP_UNSHARING. - - If there are only few specific cases of node sharing across functions, it is - probably easier for a front-end to unshare the expressions manually. On the - contrary, if the expressions generated at the global level are as widespread - as expressions generated within functions, deep unsharing is very likely the - way to go. */ - - /* Similar to copy_tree_r but do not copy SAVE_EXPR or TARGET_EXPR nodes. - These nodes model computations that must be done once. If we were to - unshare something like SAVE_EXPR(i++), the gimplification process would - create wrong code. However, if DATA is non-null, it must hold a pointer - set that is used to unshare the subtrees of these nodes. */ - - static tree - mostly_copy_tree_r (tree *tp, int *walk_subtrees, void *data) - { - tree t = *tp; - enum tree_code code = TREE_CODE (t); - - /* Do not copy SAVE_EXPR, TARGET_EXPR or BIND_EXPR nodes themselves, but - copy their subtrees if we can make sure to do it only once. */ - if (code == SAVE_EXPR || code == TARGET_EXPR || code == BIND_EXPR) - { - if (data && !pointer_set_insert ((struct pointer_set_t *)data, t)) - ; - else - *walk_subtrees = 0; - } - - /* Stop at types, decls, constants like copy_tree_r. */ - else if (TREE_CODE_CLASS (code) == tcc_type - || TREE_CODE_CLASS (code) == tcc_declaration - || TREE_CODE_CLASS (code) == tcc_constant - /* We can't do anything sensible with a BLOCK used as an - expression, but we also can't just die when we see it - because of non-expression uses. So we avert our eyes - and cross our fingers. Silly Java. */ - || code == BLOCK) - *walk_subtrees = 0; - - /* Cope with the statement expression extension. */ - else if (code == STATEMENT_LIST) - ; - - /* Leave the bulk of the work to copy_tree_r itself. */ - else - copy_tree_r (tp, walk_subtrees, NULL); - - return NULL_TREE; - } - - /* Callback for walk_tree to unshare most of the shared trees rooted at *TP. - If *TP has been visited already, then *TP is deeply copied by calling - mostly_copy_tree_r. DATA is passed to mostly_copy_tree_r unmodified. */ - - static tree - copy_if_shared_r (tree *tp, int *walk_subtrees, void *data) - { - tree t = *tp; - enum tree_code code = TREE_CODE (t); - - /* Skip types, decls, and constants. But we do want to look at their - types and the bounds of types. Mark them as visited so we properly - unmark their subtrees on the unmark pass. If we've already seen them, - don't look down further. */ - if (TREE_CODE_CLASS (code) == tcc_type - || TREE_CODE_CLASS (code) == tcc_declaration - || TREE_CODE_CLASS (code) == tcc_constant) - { - if (TREE_VISITED (t)) - *walk_subtrees = 0; - else - TREE_VISITED (t) = 1; - } - - /* If this node has been visited already, unshare it and don't look - any deeper. */ - else if (TREE_VISITED (t)) - { - walk_tree (tp, mostly_copy_tree_r, data, NULL); - *walk_subtrees = 0; - } - - /* Otherwise, mark the node as visited and keep looking. */ - else - TREE_VISITED (t) = 1; - - return NULL_TREE; - } - - /* Unshare most of the shared trees rooted at *TP. DATA is passed to the - copy_if_shared_r callback unmodified. */ - - static inline void - copy_if_shared (tree *tp, void *data) - { - walk_tree (tp, copy_if_shared_r, data, NULL); - } - - /* Unshare all the trees in the body of FNDECL, as well as in the bodies of - any nested functions. */ - - static void - unshare_body (tree fndecl) - { - struct cgraph_node *cgn = cgraph_get_node (fndecl); - /* If the language requires deep unsharing, we need a pointer set to make - sure we don't repeatedly unshare subtrees of unshareable nodes. */ - struct pointer_set_t *visited - = lang_hooks.deep_unsharing ? pointer_set_create () : NULL; - - copy_if_shared (&DECL_SAVED_TREE (fndecl), visited); - copy_if_shared (&DECL_SIZE (DECL_RESULT (fndecl)), visited); - copy_if_shared (&DECL_SIZE_UNIT (DECL_RESULT (fndecl)), visited); - - if (visited) - pointer_set_destroy (visited); - - if (cgn) - for (cgn = cgn->nested; cgn; cgn = cgn->next_nested) - unshare_body (cgn->symbol.decl); - } - /* Callback for walk_tree to unmark the visited trees rooted at *TP. Subtrees are walked until the first unvisited node is encountered. */ --- 813,818 ---- *************** unvisit_body (tree fndecl) *** 1008,1047 **** unvisit_body (cgn->symbol.decl); } - /* Unconditionally make an unshared copy of EXPR. This is used when using - stored expressions which span multiple functions, such as BINFO_VTABLE, - as the normal unsharing process can't tell that they're shared. */ - - tree - unshare_expr (tree expr) - { - walk_tree (&expr, mostly_copy_tree_r, NULL, NULL); - return expr; - } - - /* Worker for unshare_expr_without_location. */ - - static tree - prune_expr_location (tree *tp, int *walk_subtrees, void *) - { - if (EXPR_P (*tp)) - SET_EXPR_LOCATION (*tp, UNKNOWN_LOCATION); - else - *walk_subtrees = 0; - return NULL_TREE; - } - - /* Similar to unshare_expr but also prune all expression locations - from EXPR. */ - - tree - unshare_expr_without_location (tree expr) - { - walk_tree (&expr, mostly_copy_tree_r, NULL, NULL); - if (EXPR_P (expr)) - walk_tree (&expr, prune_expr_location, NULL, NULL); - return expr; - } /* WRAPPER is a code such as BIND_EXPR or CLEANUP_POINT_EXPR which can both contain statements and have a value. Assign its value to a temporary --- 856,861 ---- Index: tree.c =================================================================== *** tree.c (revision 203319) --- tree.c (working copy) *************** using_eh_for_cleanups_p (void) *** 12265,12268 **** --- 12265,12456 ---- return using_eh_for_cleanups_flag; } + /* This page contains routines to unshare tree nodes, i.e. to duplicate tree + nodes that are referenced more than once in GENERIC functions. This is + necessary because gimplification (translation into GIMPLE) is performed + by modifying tree nodes in-place, so gimplication of a shared node in a + first context could generate an invalid GIMPLE form in a second context. + + This is achieved with a simple mark/copy/unmark algorithm that walks the + GENERIC representation top-down, marks nodes with TREE_VISITED the first + time it encounters them, duplicates them if they already have TREE_VISITED + set, and finally removes the TREE_VISITED marks it has set. + + The algorithm works only at the function level, i.e. it generates a GENERIC + representation of a function with no nodes shared within the function when + passed a GENERIC function (except for nodes that are allowed to be shared). + + At the global level, it is also necessary to unshare tree nodes that are + referenced in more than one function, for the same aforementioned reason. + This requires some cooperation from the front-end. There are 2 strategies: + + 1. Manual unsharing. The front-end needs to call unshare_expr on every + expression that might end up being shared across functions. + + 2. Deep unsharing. This is an extension of regular unsharing. Instead + of calling unshare_expr on expressions that might be shared across + functions, the front-end pre-marks them with TREE_VISITED. This will + ensure that they are unshared on the first reference within functions + when the regular unsharing algorithm runs. The counterpart is that + this algorithm must look deeper than for manual unsharing, which is + specified by LANG_HOOKS_DEEP_UNSHARING. + + If there are only few specific cases of node sharing across functions, it is + probably easier for a front-end to unshare the expressions manually. On the + contrary, if the expressions generated at the global level are as widespread + as expressions generated within functions, deep unsharing is very likely the + way to go. */ + + /* Similar to copy_tree_r but do not copy SAVE_EXPR or TARGET_EXPR nodes. + These nodes model computations that must be done once. If we were to + unshare something like SAVE_EXPR(i++), the gimplification process would + create wrong code. However, if DATA is non-null, it must hold a pointer + set that is used to unshare the subtrees of these nodes. */ + + static tree + mostly_copy_tree_r (tree *tp, int *walk_subtrees, void *data) + { + tree t = *tp; + enum tree_code code = TREE_CODE (t); + + /* Do not copy SAVE_EXPR, TARGET_EXPR or BIND_EXPR nodes themselves, but + copy their subtrees if we can make sure to do it only once. */ + if (code == SAVE_EXPR || code == TARGET_EXPR || code == BIND_EXPR) + { + if (data && !pointer_set_insert ((struct pointer_set_t *)data, t)) + ; + else + *walk_subtrees = 0; + } + + /* Stop at types, decls, constants like copy_tree_r. */ + else if (TREE_CODE_CLASS (code) == tcc_type + || TREE_CODE_CLASS (code) == tcc_declaration + || TREE_CODE_CLASS (code) == tcc_constant + /* We can't do anything sensible with a BLOCK used as an + expression, but we also can't just die when we see it + because of non-expression uses. So we avert our eyes + and cross our fingers. Silly Java. */ + || code == BLOCK) + *walk_subtrees = 0; + + /* Cope with the statement expression extension. */ + else if (code == STATEMENT_LIST) + ; + + /* Leave the bulk of the work to copy_tree_r itself. */ + else + copy_tree_r (tp, walk_subtrees, NULL); + + return NULL_TREE; + } + + /* Callback for walk_tree to unshare most of the shared trees rooted at *TP. + If *TP has been visited already, then *TP is deeply copied by calling + mostly_copy_tree_r. DATA is passed to mostly_copy_tree_r unmodified. */ + + static tree + copy_if_shared_r (tree *tp, int *walk_subtrees, void *data) + { + tree t = *tp; + enum tree_code code = TREE_CODE (t); + + /* Skip types, decls, and constants. But we do want to look at their + types and the bounds of types. Mark them as visited so we properly + unmark their subtrees on the unmark pass. If we've already seen them, + don't look down further. */ + if (TREE_CODE_CLASS (code) == tcc_type + || TREE_CODE_CLASS (code) == tcc_declaration + || TREE_CODE_CLASS (code) == tcc_constant) + { + if (TREE_VISITED (t)) + *walk_subtrees = 0; + else + TREE_VISITED (t) = 1; + } + + /* If this node has been visited already, unshare it and don't look + any deeper. */ + else if (TREE_VISITED (t)) + { + walk_tree (tp, mostly_copy_tree_r, data, NULL); + *walk_subtrees = 0; + } + + /* Otherwise, mark the node as visited and keep looking. */ + else + TREE_VISITED (t) = 1; + + return NULL_TREE; + } + + /* Unshare most of the shared trees rooted at *TP. DATA is passed to the + copy_if_shared_r callback unmodified. */ + + static inline void + copy_if_shared (tree *tp, void *data) + { + walk_tree (tp, copy_if_shared_r, data, NULL); + } + + /* Unshare all the trees in the body of FNDECL, as well as in the bodies of + any nested functions. */ + + void + unshare_body (tree fndecl) + { + struct cgraph_node *cgn = cgraph_get_node (fndecl); + /* If the language requires deep unsharing, we need a pointer set to make + sure we don't repeatedly unshare subtrees of unshareable nodes. */ + struct pointer_set_t *visited + = lang_hooks.deep_unsharing ? pointer_set_create () : NULL; + + copy_if_shared (&DECL_SAVED_TREE (fndecl), visited); + copy_if_shared (&DECL_SIZE (DECL_RESULT (fndecl)), visited); + copy_if_shared (&DECL_SIZE_UNIT (DECL_RESULT (fndecl)), visited); + + if (visited) + pointer_set_destroy (visited); + + if (cgn) + for (cgn = cgn->nested; cgn; cgn = cgn->next_nested) + unshare_body (cgn->symbol.decl); + } + + + /* Unconditionally make an unshared copy of EXPR. This is used when using + stored expressions which span multiple functions, such as BINFO_VTABLE, + as the normal unsharing process can't tell that they're shared. */ + + tree + unshare_expr (tree expr) + { + walk_tree (&expr, mostly_copy_tree_r, NULL, NULL); + return expr; + } + + /* Worker for unshare_expr_without_location. */ + + static tree + prune_expr_location (tree *tp, int *walk_subtrees, void *) + { + if (EXPR_P (*tp)) + SET_EXPR_LOCATION (*tp, UNKNOWN_LOCATION); + else + *walk_subtrees = 0; + return NULL_TREE; + } + + /* Similar to unshare_expr but also prune all expression locations + from EXPR. */ + + tree + unshare_expr_without_location (tree expr) + { + walk_tree (&expr, mostly_copy_tree_r, NULL, NULL); + if (EXPR_P (expr)) + walk_tree (&expr, prune_expr_location, NULL, NULL); + return expr; + } + #include "gt-tree.h"