* 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.
===================================================================
*************** extern void cache_integer_cst (tree);
/* 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);
*************** extern bool type_in_anonymous_namespace_
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);
===================================================================
*************** annotate_all_with_location (gimple_seq s
}
}
- /* 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. */
*************** unvisit_body (tree fndecl)
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
===================================================================
*************** using_eh_for_cleanups_p (void)
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"