This is the mail archive of the gcc-patches@gcc.gnu.org mailing list for the GCC project.


Index Nav: [Date Index] [Subject Index] [Author Index] [Thread Index]
Message Nav: [Date Prev] [Date Next] [Thread Prev] [Thread Next]
Other format: [Raw text]

Re: [patch] The remainder of tree-flow.h refactored.


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"

Index Nav: [Date Index] [Subject Index] [Author Index] [Thread Index]
Message Nav: [Date Prev] [Date Next] [Thread Prev] [Thread Next]