This is the mail archive of the
gcc-patches@gcc.gnu.org
mailing list for the GCC project.
[gomp] Fix -O0 builds and private vars mapping
- From: Diego Novillo <dnovillo at redhat dot com>
- To: gcc-patches at gcc dot gnu dot org
- Date: Wed, 3 Aug 2005 19:44:44 -0400
- Subject: [gomp] Fix -O0 builds and private vars mapping
When unit at a time is disabled, we cannot call cgraph_finalize_function
directly because it will try to expand the new function while we
are expanding another one.
The new function has to be added to the call graph *and* marked
as needed. However, the call to cgraph_mark_needed_node will
refuse to add nodes that are not marked as finalized.
The patch also moves the variable mapping logic into
tree-inline.c. In the near future, I will need to abstract a
bunch of functionality out of the inliner. We are starting to
use it for quite a few things (procedure cloning, OpenMP function
outlining and inlining per-se). But I don't want to do this on
the branch, so I'll wait for mainline to be in stage 1 again to
rearrange things.
* cgraph.c (cgraph_add_new_function): When unit at a time is
disabled, just add the new function to the graph and mark it
as needed.
* gimple-low.c (struct remap_locals_d, add_decls_to_set,
build_remap_info, remap_locals_r, remap_locals_in_gomp_body):
Move ...
* tree-inline.c: ... here.
(move_decl_to): New local function.
(remap_locals_r): Call it.
* tree-inline.h (remap_locals_in_gomp_body): Declare.
Index: cgraph.c
===================================================================
RCS file: /cvs/gcc/gcc/gcc/cgraph.c,v
retrieving revision 1.77.4.3
diff -d -u -p -r1.77.4.3 cgraph.c
--- cgraph.c 28 Jul 2005 19:28:42 -0000 1.77.4.3
+++ cgraph.c 3 Aug 2005 23:32:12 -0000
@@ -1044,7 +1044,23 @@ cgraph_add_new_function (tree fndecl)
cfun->function_end_locus = input_location;
current_function_decl = fndecl;
gimplify_function_tree (fndecl);
- cgraph_finalize_function (fndecl, false);
+ if (flag_unit_at_a_time)
+ {
+ /* Add the function to the callgraph to be processed after we
+ parse all the functions in the compilation unit. */
+ cgraph_finalize_function (fndecl, false);
+ }
+ else
+ {
+ /* When not compiling the whole unit at a time, the compiler
+ will output functions right after parsing them. Since we are
+ adding a brand new function body that the parser will not
+ see, we need to make sure it's added at the end of the queue
+ of callgraph nodes to be expanded. */
+ struct cgraph_node *n = cgraph_node (fndecl);
+ n->local.finalized = 1;
+ cgraph_mark_needed_node (n);
+ }
/* Restore CFUN and CURRENT_FUNCTION_DECL. */
cfun = saved_cfun;
Index: gimple-low.c
===================================================================
RCS file: /cvs/gcc/gcc/gcc/gimple-low.c,v
retrieving revision 2.24.4.3
diff -d -u -p -r2.24.4.3 gimple-low.c
--- gimple-low.c 1 Aug 2005 21:39:03 -0000 2.24.4.3
+++ gimple-low.c 3 Aug 2005 23:32:12 -0000
@@ -154,139 +154,6 @@ lower_stmt_body (tree expr, struct lower
}
-/* Data structure used for remap_locals_r. */
-
-struct remap_locals_d
-{
- /* FUNCTION_DECL of the new artificial function containing the
- pragma's body. */
- tree gomp_fn;
-
- /* Sets of DECLs representing the different data sharing clauses. */
- bitmap private;
- bitmap firstprivate;
- bitmap lastprivate;
- bitmap shared;
-
- /* Sets of DECLs representing the different data copying clauses. */
- bitmap copyin;
- bitmap copyprivate;
-};
-
-
-/* Add all the variables in LIST to the bitmap *SET_P. Create a new
- bitmap, if necessary. */
-
-static void
-add_decls_to_set (bitmap *set_p, tree list)
-{
- tree t;
-
- if (*set_p == NULL)
- *set_p = BITMAP_ALLOC (NULL);
-
- for (t = list; t; t = TREE_CHAIN (t))
- {
- tree var = TREE_VALUE (t);
- bitmap_set_bit (*set_p, DECL_UID (var));
- }
-}
-
-
-/* Fill in all the data sharing and copying bitmaps in REMAP_INFO_P
- using the clauses in LIST. */
-
-static void
-build_remap_info (struct remap_locals_d *remap_info_p, tree list)
-{
- tree c;
-
- for (c = list; c; c = TREE_CHAIN (c))
- {
- tree clause = TREE_VALUE (c);
- bitmap *set_p = NULL;
-
- if (TREE_CODE (clause) == GOMP_CLAUSE_PRIVATE)
- set_p = &remap_info_p->private;
- else if (TREE_CODE (clause) == GOMP_CLAUSE_SHARED)
- set_p = &remap_info_p->shared;
- else if (TREE_CODE (clause) == GOMP_CLAUSE_FIRSTPRIVATE)
- set_p = &remap_info_p->firstprivate;
- else if (TREE_CODE (clause) == GOMP_CLAUSE_LASTPRIVATE)
- set_p = &remap_info_p->lastprivate;
- else if (TREE_CODE (clause) == GOMP_CLAUSE_COPYIN)
- set_p = &remap_info_p->copyin;
- else if (TREE_CODE (clause) == GOMP_CLAUSE_COPYPRIVATE)
- set_p = &remap_info_p->copyprivate;
-
- if (set_p)
- add_decls_to_set (set_p, TREE_OPERAND (clause, 0));
- }
-
- /* FIXME. Add checking code to disallow variables in multiple sets.
- Variables may only appear in exactly one set, except for
- firstprivate and lastprivate. */
-}
-
-
-/* Callback for walk_tree to change the context of all the local
- variables found in *TP accordingly to what is described by the
- data clauses of DATA.GOMP_EXPR. */
-
-static tree
-remap_locals_r (tree *tp, int *ws ATTRIBUTE_UNUSED, void *data)
-{
- struct remap_locals_d *remap_info = (struct remap_locals_d *)data;
- tree t, gomp_fn;
-
- gomp_fn = remap_info->gomp_fn;
-
- t = *tp;
- if (TREE_CODE (t) == PARM_DECL)
- {
- gcc_unreachable ();
- }
- else if (TREE_CODE (t) == VAR_DECL
- && !is_global_var (t)
- && decl_function_context (t) != gomp_fn)
- {
- struct function *f = DECL_STRUCT_FUNCTION (gomp_fn);
- DECL_CONTEXT (t) = gomp_fn;
- f->unexpanded_var_list = tree_cons (NULL_TREE, t, f->unexpanded_var_list);
- }
-
- return NULL;
-}
-
-
-/* Rewrite references to local variables inside the body of GOMP_EXPR
- using the data sharing information from the directive clauses.
- GOMP_FN is the compiler generated function that contains the body
- of GOMP_EXPR. */
-
-static void
-remap_locals_in_gomp_body (tree gomp_expr, tree gomp_fn)
-{
- tree_stmt_iterator i;
- struct remap_locals_d remap_info;
- tree body = GOMP_PARALLEL_BODY (gomp_expr);
-
- memset (&remap_info, 0, sizeof (remap_info));
- remap_info.gomp_fn = gomp_fn;
-
- /* Build the sets of data sharing clauses. */
- build_remap_info (&remap_info, GOMP_PARALLEL_CLAUSES (gomp_expr));
-
- /* Rewrite all the private local variables so that their context is
- GOMP_FN. */
- for (i = tsi_start (body); !tsi_end_p (i); tsi_next (&i))
- walk_tree (tsi_stmt_ptr (i), remap_locals_r, &remap_info, NULL);
-
- /* Add initialization/finalization code in GOMP_FN to model copyin,
- firstprivate and lastprivate. */
-}
-
-
/* Build a new nested function to hold the body of GOMP_EXPR (an
OpenMP pragma). The new function is added to the call graph and
the FUNCTION_DECL representing it, returned. */
Index: tree-inline.c
===================================================================
RCS file: /cvs/gcc/gcc/gcc/tree-inline.c,v
retrieving revision 1.192.4.3
diff -d -u -p -r1.192.4.3 tree-inline.c
--- tree-inline.c 28 Jul 2005 19:30:23 -0000 1.192.4.3
+++ tree-inline.c 3 Aug 2005 23:32:12 -0000
@@ -2620,3 +2620,203 @@ inlining_p (inline_data *id)
{
return (!id->saving_p && !id->cloning_p);
}
+
+
+/* Data structure used for remap_locals_r. */
+
+struct remap_locals_d
+{
+ /* Structure used by the inliner to create mapping between decls
+ when moving them into the artificial function representing the
+ body of an OpenMP directive. */
+ inline_data id;
+
+ /* Sets of DECLs representing the different data sharing clauses. */
+ bitmap private;
+ bitmap firstprivate;
+ bitmap lastprivate;
+ bitmap shared;
+
+ /* Sets of DECLs representing the different data copying clauses. */
+ bitmap copyin;
+ bitmap copyprivate;
+};
+
+
+/* Add all the variables in LIST to the bitmap *SET_P. Create a new
+ bitmap, if necessary. */
+
+static void
+add_decls_to_set (bitmap *set_p, tree list)
+{
+ tree t;
+
+ if (*set_p == NULL)
+ *set_p = BITMAP_ALLOC (NULL);
+
+ for (t = list; t; t = TREE_CHAIN (t))
+ {
+ tree var = TREE_VALUE (t);
+ bitmap_set_bit (*set_p, DECL_UID (var));
+ }
+}
+
+
+/* Fill in all the data sharing and copying bitmaps in REMAP_INFO_P
+ using the clauses in LIST. */
+
+static void
+build_remap_info (struct remap_locals_d *remap_info_p, tree list)
+{
+ tree c;
+
+ for (c = list; c; c = TREE_CHAIN (c))
+ {
+ tree clause = TREE_VALUE (c);
+ bitmap *set_p = NULL;
+
+ if (TREE_CODE (clause) == GOMP_CLAUSE_PRIVATE)
+ set_p = &remap_info_p->private;
+ else if (TREE_CODE (clause) == GOMP_CLAUSE_SHARED)
+ set_p = &remap_info_p->shared;
+ else if (TREE_CODE (clause) == GOMP_CLAUSE_FIRSTPRIVATE)
+ set_p = &remap_info_p->firstprivate;
+ else if (TREE_CODE (clause) == GOMP_CLAUSE_LASTPRIVATE)
+ set_p = &remap_info_p->lastprivate;
+ else if (TREE_CODE (clause) == GOMP_CLAUSE_COPYIN)
+ set_p = &remap_info_p->copyin;
+ else if (TREE_CODE (clause) == GOMP_CLAUSE_COPYPRIVATE)
+ set_p = &remap_info_p->copyprivate;
+
+ if (set_p)
+ add_decls_to_set (set_p, TREE_OPERAND (clause, 0));
+ }
+
+ /* FIXME. Add checking code to disallow variables in multiple sets.
+ Variables may only appear in exactly one set, except for
+ firstprivate and lastprivate. */
+}
+
+
+/* Move local variable VAR from ID->CALLEE into ID->CALLER. If VAR had
+ not been mapped before, add it to the unexpanded variable list in
+ ID->CALLER. Return a new VAR_DECL declared inside ID->CALLER to
+ replace VAR. */
+
+static tree
+move_decl_to (tree var, inline_data *id)
+{
+ tree new_decl;
+ bool first_time_p;
+
+ first_time_p = (splay_tree_lookup (id->decl_map, (splay_tree_key) var) != 0);
+ new_decl = remap_decl (var, id);
+
+ /* If this is the first time that we map VAR, add it to the
+ unexpanded variable list for ID->CALLER. */
+ if (first_time_p)
+ {
+ struct function *f = DECL_STRUCT_FUNCTION (id->caller);
+ DECL_CONTEXT (new_decl) = id->caller;
+ DECL_SEEN_IN_BIND_EXPR_P (new_decl) = 1;
+ f->unexpanded_var_list = tree_cons (NULL_TREE, new_decl,
+ f->unexpanded_var_list);
+ }
+
+ return new_decl;
+}
+
+
+/* Callback for walk_tree to change the context of all the local
+ variables found in *TP accordingly to what is described by the
+ sets in DATA. */
+
+static tree
+remap_locals_r (tree *tp, int *ws ATTRIBUTE_UNUSED, void *data)
+{
+ struct remap_locals_d *remap_info = (struct remap_locals_d *)data;
+ tree t, gomp_fn;
+
+ gomp_fn = remap_info->id.caller;
+
+ t = *tp;
+ if (TREE_CODE (t) == PARM_DECL)
+ {
+ gcc_unreachable ();
+ }
+ else if (TREE_CODE (t) == VAR_DECL && !is_global_var (t))
+ {
+ tree new_decl = NULL_TREE;
+
+ /* Remap local variables into GOMP_FN if they appear in one of
+ the private sets. */
+ if (remap_info->private
+ && bitmap_bit_p (remap_info->private, DECL_UID (t)))
+ {
+ /* Private variables need only be declared inside GOMP_FN. */
+ new_decl = move_decl_to (t, &remap_info->id);
+ }
+ else if (remap_info->firstprivate
+ && bitmap_bit_p (remap_info->firstprivate, DECL_UID (t)))
+ gcc_unreachable ();
+ else if (remap_info->lastprivate
+ && bitmap_bit_p (remap_info->lastprivate, DECL_UID (t)))
+ gcc_unreachable ();
+ else if (remap_info->shared
+ && bitmap_bit_p (remap_info->shared, DECL_UID (t)))
+ gcc_unreachable ();
+ else if (remap_info->copyin
+ && bitmap_bit_p (remap_info->copyin, DECL_UID (t)))
+ gcc_unreachable ();
+ else if (remap_info->copyprivate
+ && bitmap_bit_p (remap_info->copyprivate, DECL_UID (t)))
+ gcc_unreachable ();
+
+ if (new_decl)
+ *tp = new_decl;
+ }
+
+ return NULL;
+}
+
+
+/* Rewrite references to local variables inside the body of GOMP_EXPR
+ using the data sharing information from the directive clauses.
+ GOMP_FN is the compiler generated function that contains the body
+ of GOMP_EXPR. */
+
+void
+remap_locals_in_gomp_body (tree gomp_expr, tree gomp_fn)
+{
+ tree_stmt_iterator i;
+ struct remap_locals_d remap_info;
+ tree body = GOMP_PARALLEL_BODY (gomp_expr);
+
+ /* Setup an INLINE_DATA structure to use the generic DECL mapping
+ functions used by the inliner.
+
+ Notice that since we are outlining the body of GOMP_EXPR into
+ GOMP_FN, we are doing the opposite operation to inlining. So, we
+ need to switch the roles of CALLEE and CALLER in the inline_data
+ structure to get the desired effect in functions like remap_decl.
+
+ FIXME, the fields CALLER and CALLEE need to be renamed and the
+ generic utility functions in the inliner need to be made more
+ independent. These functions are now used for procedure cloning,
+ outlining of OpenMP directives and inlining. */
+ memset (&remap_info, 0, sizeof (remap_info));
+ remap_info.id.callee = current_function_decl;
+ remap_info.id.caller = gomp_fn;
+ remap_info.id.decl_map = splay_tree_new (splay_tree_compare_pointers, 0, 0);
+
+ /* Build the sets of data sharing clauses. */
+ build_remap_info (&remap_info, GOMP_PARALLEL_CLAUSES (gomp_expr));
+
+ /* Rewrite all the private local variables so that their context is
+ GOMP_FN. */
+ for (i = tsi_start (body); !tsi_end_p (i); tsi_next (&i))
+ walk_tree (tsi_stmt_ptr (i), remap_locals_r, &remap_info, NULL);
+
+ /* Add initialization/finalization code in GOMP_FN to model copyin,
+ firstprivate and lastprivate. */
+}
Index: tree-inline.h
===================================================================
RCS file: /cvs/gcc/gcc/gcc/tree-inline.h,v
retrieving revision 1.17.4.1
diff -d -u -p -r1.17.4.1 tree-inline.h
--- tree-inline.h 6 Jul 2005 17:39:40 -0000 1.17.4.1
+++ tree-inline.h 3 Aug 2005 23:32:12 -0000
@@ -33,6 +33,7 @@ int estimate_move_cost (tree type);
void push_cfun (struct function *new_cfun);
void pop_cfun (void);
int estimate_num_insns (tree expr);
+void remap_locals_in_gomp_body (tree, tree);
/* 0 if we should not perform inlining.
1 if we should expand functions calls inline at the tree level.