#include "tree-pass.h"
#include "print-rtl.h"
#include "rtl-iter.h"
-#include "gimplify.h"
#include "profile.h"
#include "sreal.h"
#include "gimple-walk.h"
#include "ipa-utils.h"
#include "except.h"
-#include "gimplify.h"
/* Context of record_reference. */
struct record_reference_ctx
#include "rtx-vector-builder.h"
#include "gimple.h"
#include "gimple-ssa.h"
-#include "gimplify.h"
#include "bbitmap.h"
struct target_rtl default_target_rtl;
}
}
-
-\f
-/* 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 gimplification 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 && !((hash_set<tree> *)data)->add (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)
- *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. */
-
-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. */
unvisit_body (cgn->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;
-}
-
/* Return the EXPR_LOCATION of EXPR, if it (maybe recursively) has
one, OR_ELSE otherwise. The location of a STATEMENT_LISTs
comprising at least one DEBUG_BEGIN_STMT followed by exactly one
extern void declare_vars (tree, gimple *, bool);
extern void gimple_add_tmp_var (tree);
extern void gimple_add_tmp_var_fn (struct function *, tree);
-extern void copy_if_shared (tree *, void * = NULL);
-extern tree unshare_expr (tree);
-extern tree unshare_expr_without_location (tree);
extern tree voidify_wrapper_expr (tree, tree);
extern tree build_and_jump (tree *);
extern enum gimplify_status gimplify_self_mod_expr (tree *, gimple_seq *,
#include "tree-ssa-scopedtables.h"
#include "tree-ssa-threadedge.h"
#include "tree-ssa-dom.h"
-#include "gimplify.h"
#include "tree-cfgcleanup.h"
#include "dbgcnt.h"
#include "alloc-pool.h"
#include "tree-ssa-dse.h"
#include "builtins.h"
#include "gimple-fold.h"
-#include "gimplify.h"
#include "tree-eh.h"
#include "cfganal.h"
#include "cgraph.h"
#include "fold-const.h"
#include "cfganal.h"
#include "tree-eh.h"
-#include "gimplify.h"
#include "gimple-iterator.h"
#include "tree-cfg.h"
#include "tree-ssa-loop-manip.h"
#include "fold-const.h"
#include "calls.h"
#include "intl.h"
-#include "gimplify.h"
#include "gimple-iterator.h"
#include "tree-cfg.h"
#include "tree-ssa-loop-ivopts.h"
#include "tree-pass.h"
#include "ssa.h"
#include "fold-const.h"
-#include "gimplify.h"
#include "tree-cfg.h"
#include "tree-ssa.h"
#include "tree-ssa-loop-niter.h"
#include "fold-const.h"
#include "gimple-iterator.h"
#include "gimple-fold.h"
-#include "gimplify.h"
-#include "gimplify-me.h"
#include "stor-layout.h"
#include "tree-cfg.h"
#include "tree-dfa.h"
#include "fold-const.h"
#include "stor-layout.h"
#include "cfganal.h"
-#include "gimplify.h"
#include "gimple-iterator.h"
-#include "gimplify-me.h"
#include "tree-cfg.h"
#include "tree-dfa.h"
#include "domwalk.h"
#include "gimple-pretty-print.h"
#include "fold-const.h"
#include "tree-eh.h"
-#include "gimplify.h"
#include "gimple-iterator.h"
#include "stor-layout.h"
#include "tree-ssa-loop.h"
#include "gimple-iterator.h"
#include "gimple-fold.h"
#include "tree-eh.h"
-#include "gimplify.h"
#include "tree-cfg.h"
#include "tree-into-ssa.h"
#include "tree-dfa.h"
#include "gimple-iterator.h"
#include "gimple-fold.h"
#include "tree-eh.h"
-#include "gimplify.h"
#include "tree-cfg.h"
#include "tree-ssa.h"
#include "tree-ssa-propagate.h"
#include "gimple-iterator.h"
#include "gimple-fold.h"
#include "tree-eh.h"
-#include "gimplify.h"
#include "flags.h"
#include "dojump.h"
#include "explow.h"
(old_target_attr, old_decl, new_target_attr, new_decl);
}
+\f
+/* 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 gimplification 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 && !((hash_set<tree> *)data)->add (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)
+ *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. */
+
+void
+copy_if_shared (tree *tp, void *data)
+{
+ walk_tree (tp, copy_if_shared_r, data, NULL);
+}
+
+/* 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;
+}
+
void
tree_cc_finalize (void)
{
/* Checks if two overlapping decls are not mergeable. */
extern bool diagnose_versioned_decls (tree, tree);
+/* Unshare tree if needed. */
+extern tree unshare_expr (tree);
+
+/* Unshare tree if needed.
+ Removing the locations if an expr. */
+extern tree unshare_expr_without_location (tree);
+
+extern void copy_if_shared (tree *, void * = NULL);
+
#endif /* GCC_TREE_H */