]> git.ipfire.org Git - thirdparty/gcc.git/commitdiff
tree: Move unshare_expr from gimplifier to generic tree
authorAndrew Pinski <andrew.pinski@oss.qualcomm.com>
Sun, 17 May 2026 21:32:33 +0000 (14:32 -0700)
committerAndrew Pinski <andrew.pinski@oss.qualcomm.com>
Tue, 19 May 2026 08:23:20 +0000 (01:23 -0700)
We use unshare_expr in many places now outside of gimple
even. So it makes sense to move the decl to tree.h.
A few sources can now even not need to include gimplify.h;
I have not checked all of them just a few which seemed
like including gimplify.h didn't make sense.

This also moves the implementations of unshare_expr,
unshare_expr_without_location and copy_if_shared from gimplify.cc
to tree.cc to keep the headers "clean".

Bootstrapped and tested on x86_64-linux-gnu.

Changes since v1:
 * v2: Move implementation too.

gcc/ChangeLog:

* cfgrtl.cc: Don't include gimplify.h or gimplify-me.h.
* cgraphbuild.cc: Likewise.
* emit-rtl.cc: Likewie.
* tree-ssa-dom.cc: Likewise.
* tree-ssa-dse.cc: Likewise.
* tree-ssa-loop-im.cc: Likewise.
* tree-ssa-loop-niter.cc: Likewise.
* tree-ssa-loop-unswitch.cc: Likewise.
* tree-ssa-math-opts.cc: Likewise.
* tree-ssa-phiopt.cc: Likewise.
* tree-ssa-phiprop.cc: Likewise.
* tree-ssa-pre.cc: Likewise.
* tree-ssa-propagate.cc: Likewise.
* tree-ssa-sccvn.cc: Likewise.
* gimplify.h (unshare_expr): Remove.
(unshare_expr_without_location): Remove.
(copy_if_shared): Remove.
* tree.h (unshare_expr): New decl.
(unshare_expr_without_location): Likewise.
(copy_if_shared): Likewise.
* gimplify.cc (mostly_copy_tree_r): Moved to tree.cc.
(copy_if_shared_r): Likewise.
(copy_if_shared): Likewise.
(unshare_expr): Likewise.
(prune_expr_location): Likewise.
(unshare_expr_without_location): Likewise.
* tree.cc (mostly_copy_tree_r): Moved from gimplify.cc
(copy_if_shared_r): Likewise.
(copy_if_shared): Likewise.
(unshare_expr): Likewise.
(prune_expr_location): Likewise.
(unshare_expr_without_location): Likewise.

Signed-off-by: Andrew Pinski <andrew.pinski@oss.qualcomm.com>
18 files changed:
gcc/cfgrtl.cc
gcc/cgraphbuild.cc
gcc/emit-rtl.cc
gcc/gimplify.cc
gcc/gimplify.h
gcc/tree-ssa-dom.cc
gcc/tree-ssa-dse.cc
gcc/tree-ssa-loop-im.cc
gcc/tree-ssa-loop-niter.cc
gcc/tree-ssa-loop-unswitch.cc
gcc/tree-ssa-math-opts.cc
gcc/tree-ssa-phiopt.cc
gcc/tree-ssa-phiprop.cc
gcc/tree-ssa-pre.cc
gcc/tree-ssa-propagate.cc
gcc/tree-ssa-sccvn.cc
gcc/tree.cc
gcc/tree.h

index 7714e5548c2dd5ce2588199902fdd3eec101041b..0ec72f08fa873b978c82bea6d94ea5911c30f07b 100644 (file)
@@ -62,7 +62,6 @@ along with GCC; see the file COPYING3.  If not see
 #include "tree-pass.h"
 #include "print-rtl.h"
 #include "rtl-iter.h"
-#include "gimplify.h"
 #include "profile.h"
 #include "sreal.h"
 
index e33a414310bc77dcda71176ccda6a6009caef392..3faf8395db5e4d777402be27e7d0ae19e83c877f 100644 (file)
@@ -31,7 +31,6 @@ along with GCC; see the file COPYING3.  If not see
 #include "gimple-walk.h"
 #include "ipa-utils.h"
 #include "except.h"
-#include "gimplify.h"
 
 /* Context of record_reference.  */
 struct record_reference_ctx
index e41ec2283b8fa3cf97ed04c270308131701dc003..7f5d267341ac30afbd25c65bec2910f5b6ce3150 100644 (file)
@@ -63,7 +63,6 @@ along with GCC; see the file COPYING3.  If not see
 #include "rtx-vector-builder.h"
 #include "gimple.h"
 #include "gimple-ssa.h"
-#include "gimplify.h"
 #include "bbitmap.h"
 
 struct target_rtl default_target_rtl;
index e4db4b1d9bd2c5ecb52847ef338ce00800375278..cdd039eb2bde8df2694381827e0ab7c2abe6a4f7 100644 (file)
@@ -896,131 +896,6 @@ gimple_add_tmp_var (tree tmp)
     }
 }
 
-
-\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.  */
 
@@ -1089,41 +964,6 @@ unvisit_body (tree fndecl)
       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
index caa35b426bd60e8843996bedf6cd2bbd9687855b..18c7514c9a3e6aeec76adac3d270cf138b155757 100644 (file)
@@ -62,9 +62,6 @@ extern tree get_initialized_tmp_var (tree, gimple_seq *, gimple_seq * = NULL,
 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 *,
index 3be7979f5289f72f8a4ceeb8d973d94aa91be06d..37a29697319b47ca18c33661de2c84ea078130ff 100644 (file)
@@ -42,7 +42,6 @@ along with GCC; see the file COPYING3.  If not see
 #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"
index 58cfa9ec129b9f0ea0d07eb246a46ab4f9253d0e..2f97d6d1a1ab9e91b8592099418c799f91ceceb8 100644 (file)
@@ -37,7 +37,6 @@ along with GCC; see the file COPYING3.  If not see
 #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"
index 4f7401e2d5d3e932f5befc2326b615867d4de828..2651e3919e3abfad1eb396c983c898e6a536bec1 100644 (file)
@@ -30,7 +30,6 @@ along with GCC; see the file COPYING3.  If not see
 #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"
index c39401147aedb4ff8e3001a9048d72b68b5d5d04..f179be1ffc7cf2e6e5c279695387d99096548138 100644 (file)
@@ -32,7 +32,6 @@ along with GCC; see the file COPYING3.  If not see
 #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"
index 96680bc64ea37d7747095e0d81f77f2c63e4bc9e..a18c9ccfffa48e6f81f032188cdd976e92a6e373 100644 (file)
@@ -26,7 +26,6 @@ along with GCC; see the file COPYING3.  If not see
 #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"
index cd3fd2fc8fb4ce158466162648e3edbfcb218735..72f6dbd1a990704fe394f6b83d1c15a8b0d38d5f 100644 (file)
@@ -102,8 +102,6 @@ along with GCC; see the file COPYING3.  If not see
 #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"
index e654e82363606c04d5f98e1a64522a9c9f695960..18b5f284eee48eb05a496ed46ece82535e306844 100644 (file)
@@ -35,9 +35,7 @@ along with GCC; see the file COPYING3.  If not see
 #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"
index 54f3ad8d9f8411af547455783fc43f547990f909..7e7a4534eb2baee119aae135770f64807aa417c4 100644 (file)
@@ -29,7 +29,6 @@ along with GCC; see the file COPYING3.  If not see
 #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"
index 0e5eaf86bc7e56e2740b445eefbb4298cc35d5f5..5ded68443ddc1dc024c3fd1b80c3dc244366f180 100644 (file)
@@ -37,7 +37,6 @@ along with GCC; see the file COPYING3.  If not see
 #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"
index a87c45d3a122cae97cf2ab9e19d8cad68ec131e8..992b4243670e658ea17e37da47f9fcf868428a73 100644 (file)
@@ -30,7 +30,6 @@
 #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"
index e19beb439d20a89e6010261a09a366cc945b9e8e..79b6b465294648030d3b96f3ea2ec84ca63b9a47 100644 (file)
@@ -42,7 +42,6 @@ along with GCC; see the file COPYING3.  If not see
 #include "gimple-iterator.h"
 #include "gimple-fold.h"
 #include "tree-eh.h"
-#include "gimplify.h"
 #include "flags.h"
 #include "dojump.h"
 #include "explow.h"
index 8479ffab584fd22e4cc337f8b5f91dc829c75290..e3df004be973657be897dc73c76cc47a194d8752 100644 (file)
@@ -15847,6 +15847,165 @@ diagnose_versioned_decls (tree old_decl, tree new_decl)
            (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)
 {
index 3b012d0fd6adfc2290a372139cb0fb1d3ac98650..05400ada20ba44cbe0c84baa6f04c13f0344d2b5 100644 (file)
@@ -7204,4 +7204,13 @@ extern bool disjoint_version_decls (tree, tree);
 /* 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  */