1e4b17023SJohn Marino /* Lowering pass for OpenMP directives. Converts OpenMP directives
2e4b17023SJohn Marino into explicit calls to the runtime library (libgomp) and data
3e4b17023SJohn Marino marshalling to implement data sharing and copying clauses.
4e4b17023SJohn Marino Contributed by Diego Novillo <dnovillo@redhat.com>
5e4b17023SJohn Marino
6e4b17023SJohn Marino Copyright (C) 2005, 2006, 2007, 2008, 2009, 2010, 2011, 2012
7e4b17023SJohn Marino Free Software Foundation, Inc.
8e4b17023SJohn Marino
9e4b17023SJohn Marino This file is part of GCC.
10e4b17023SJohn Marino
11e4b17023SJohn Marino GCC is free software; you can redistribute it and/or modify it under
12e4b17023SJohn Marino the terms of the GNU General Public License as published by the Free
13e4b17023SJohn Marino Software Foundation; either version 3, or (at your option) any later
14e4b17023SJohn Marino version.
15e4b17023SJohn Marino
16e4b17023SJohn Marino GCC is distributed in the hope that it will be useful, but WITHOUT ANY
17e4b17023SJohn Marino WARRANTY; without even the implied warranty of MERCHANTABILITY or
18e4b17023SJohn Marino FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
19e4b17023SJohn Marino for more details.
20e4b17023SJohn Marino
21e4b17023SJohn Marino You should have received a copy of the GNU General Public License
22e4b17023SJohn Marino along with GCC; see the file COPYING3. If not see
23e4b17023SJohn Marino <http://www.gnu.org/licenses/>. */
24e4b17023SJohn Marino
25e4b17023SJohn Marino #include "config.h"
26e4b17023SJohn Marino #include "system.h"
27e4b17023SJohn Marino #include "coretypes.h"
28e4b17023SJohn Marino #include "tm.h"
29e4b17023SJohn Marino #include "tree.h"
30e4b17023SJohn Marino #include "rtl.h"
31e4b17023SJohn Marino #include "gimple.h"
32e4b17023SJohn Marino #include "tree-iterator.h"
33e4b17023SJohn Marino #include "tree-inline.h"
34e4b17023SJohn Marino #include "langhooks.h"
35e4b17023SJohn Marino #include "diagnostic-core.h"
36e4b17023SJohn Marino #include "tree-flow.h"
37e4b17023SJohn Marino #include "timevar.h"
38e4b17023SJohn Marino #include "flags.h"
39e4b17023SJohn Marino #include "function.h"
40e4b17023SJohn Marino #include "expr.h"
41e4b17023SJohn Marino #include "tree-pass.h"
42e4b17023SJohn Marino #include "ggc.h"
43e4b17023SJohn Marino #include "except.h"
44e4b17023SJohn Marino #include "splay-tree.h"
45e4b17023SJohn Marino #include "optabs.h"
46e4b17023SJohn Marino #include "cfgloop.h"
47e4b17023SJohn Marino
48e4b17023SJohn Marino
49e4b17023SJohn Marino /* Lowering of OpenMP parallel and workshare constructs proceeds in two
50e4b17023SJohn Marino phases. The first phase scans the function looking for OMP statements
51e4b17023SJohn Marino and then for variables that must be replaced to satisfy data sharing
52e4b17023SJohn Marino clauses. The second phase expands code for the constructs, as well as
53e4b17023SJohn Marino re-gimplifying things when variables have been replaced with complex
54e4b17023SJohn Marino expressions.
55e4b17023SJohn Marino
56e4b17023SJohn Marino Final code generation is done by pass_expand_omp. The flowgraph is
57e4b17023SJohn Marino scanned for parallel regions which are then moved to a new
58e4b17023SJohn Marino function, to be invoked by the thread library. */
59e4b17023SJohn Marino
60e4b17023SJohn Marino /* Context structure. Used to store information about each parallel
61e4b17023SJohn Marino directive in the code. */
62e4b17023SJohn Marino
63e4b17023SJohn Marino typedef struct omp_context
64e4b17023SJohn Marino {
65e4b17023SJohn Marino /* This field must be at the beginning, as we do "inheritance": Some
66e4b17023SJohn Marino callback functions for tree-inline.c (e.g., omp_copy_decl)
67e4b17023SJohn Marino receive a copy_body_data pointer that is up-casted to an
68e4b17023SJohn Marino omp_context pointer. */
69e4b17023SJohn Marino copy_body_data cb;
70e4b17023SJohn Marino
71e4b17023SJohn Marino /* The tree of contexts corresponding to the encountered constructs. */
72e4b17023SJohn Marino struct omp_context *outer;
73e4b17023SJohn Marino gimple stmt;
74e4b17023SJohn Marino
75e4b17023SJohn Marino /* Map variables to fields in a structure that allows communication
76e4b17023SJohn Marino between sending and receiving threads. */
77e4b17023SJohn Marino splay_tree field_map;
78e4b17023SJohn Marino tree record_type;
79e4b17023SJohn Marino tree sender_decl;
80e4b17023SJohn Marino tree receiver_decl;
81e4b17023SJohn Marino
82e4b17023SJohn Marino /* These are used just by task contexts, if task firstprivate fn is
83e4b17023SJohn Marino needed. srecord_type is used to communicate from the thread
84e4b17023SJohn Marino that encountered the task construct to task firstprivate fn,
85e4b17023SJohn Marino record_type is allocated by GOMP_task, initialized by task firstprivate
86e4b17023SJohn Marino fn and passed to the task body fn. */
87e4b17023SJohn Marino splay_tree sfield_map;
88e4b17023SJohn Marino tree srecord_type;
89e4b17023SJohn Marino
90e4b17023SJohn Marino /* A chain of variables to add to the top-level block surrounding the
91e4b17023SJohn Marino construct. In the case of a parallel, this is in the child function. */
92e4b17023SJohn Marino tree block_vars;
93e4b17023SJohn Marino
94e4b17023SJohn Marino /* What to do with variables with implicitly determined sharing
95e4b17023SJohn Marino attributes. */
96e4b17023SJohn Marino enum omp_clause_default_kind default_kind;
97e4b17023SJohn Marino
98e4b17023SJohn Marino /* Nesting depth of this context. Used to beautify error messages re
99e4b17023SJohn Marino invalid gotos. The outermost ctx is depth 1, with depth 0 being
100e4b17023SJohn Marino reserved for the main body of the function. */
101e4b17023SJohn Marino int depth;
102e4b17023SJohn Marino
103e4b17023SJohn Marino /* True if this parallel directive is nested within another. */
104e4b17023SJohn Marino bool is_nested;
105e4b17023SJohn Marino } omp_context;
106e4b17023SJohn Marino
107e4b17023SJohn Marino
108e4b17023SJohn Marino struct omp_for_data_loop
109e4b17023SJohn Marino {
110e4b17023SJohn Marino tree v, n1, n2, step;
111e4b17023SJohn Marino enum tree_code cond_code;
112e4b17023SJohn Marino };
113e4b17023SJohn Marino
114e4b17023SJohn Marino /* A structure describing the main elements of a parallel loop. */
115e4b17023SJohn Marino
116e4b17023SJohn Marino struct omp_for_data
117e4b17023SJohn Marino {
118e4b17023SJohn Marino struct omp_for_data_loop loop;
119e4b17023SJohn Marino tree chunk_size;
120e4b17023SJohn Marino gimple for_stmt;
121e4b17023SJohn Marino tree pre, iter_type;
122e4b17023SJohn Marino int collapse;
123e4b17023SJohn Marino bool have_nowait, have_ordered;
124e4b17023SJohn Marino enum omp_clause_schedule_kind sched_kind;
125e4b17023SJohn Marino struct omp_for_data_loop *loops;
126e4b17023SJohn Marino };
127e4b17023SJohn Marino
128e4b17023SJohn Marino
129e4b17023SJohn Marino static splay_tree all_contexts;
130e4b17023SJohn Marino static int taskreg_nesting_level;
131e4b17023SJohn Marino struct omp_region *root_omp_region;
132e4b17023SJohn Marino static bitmap task_shared_vars;
133e4b17023SJohn Marino
134e4b17023SJohn Marino static void scan_omp (gimple_seq, omp_context *);
135e4b17023SJohn Marino static tree scan_omp_1_op (tree *, int *, void *);
136e4b17023SJohn Marino
137e4b17023SJohn Marino #define WALK_SUBSTMTS \
138e4b17023SJohn Marino case GIMPLE_BIND: \
139e4b17023SJohn Marino case GIMPLE_TRY: \
140e4b17023SJohn Marino case GIMPLE_CATCH: \
141e4b17023SJohn Marino case GIMPLE_EH_FILTER: \
142e4b17023SJohn Marino case GIMPLE_TRANSACTION: \
143e4b17023SJohn Marino /* The sub-statements for these should be walked. */ \
144e4b17023SJohn Marino *handled_ops_p = false; \
145e4b17023SJohn Marino break;
146e4b17023SJohn Marino
147e4b17023SJohn Marino /* Convenience function for calling scan_omp_1_op on tree operands. */
148e4b17023SJohn Marino
149e4b17023SJohn Marino static inline tree
scan_omp_op(tree * tp,omp_context * ctx)150e4b17023SJohn Marino scan_omp_op (tree *tp, omp_context *ctx)
151e4b17023SJohn Marino {
152e4b17023SJohn Marino struct walk_stmt_info wi;
153e4b17023SJohn Marino
154e4b17023SJohn Marino memset (&wi, 0, sizeof (wi));
155e4b17023SJohn Marino wi.info = ctx;
156e4b17023SJohn Marino wi.want_locations = true;
157e4b17023SJohn Marino
158e4b17023SJohn Marino return walk_tree (tp, scan_omp_1_op, &wi, NULL);
159e4b17023SJohn Marino }
160e4b17023SJohn Marino
161e4b17023SJohn Marino static void lower_omp (gimple_seq, omp_context *);
162e4b17023SJohn Marino static tree lookup_decl_in_outer_ctx (tree, omp_context *);
163e4b17023SJohn Marino static tree maybe_lookup_decl_in_outer_ctx (tree, omp_context *);
164e4b17023SJohn Marino
165e4b17023SJohn Marino /* Find an OpenMP clause of type KIND within CLAUSES. */
166e4b17023SJohn Marino
167e4b17023SJohn Marino tree
find_omp_clause(tree clauses,enum omp_clause_code kind)168e4b17023SJohn Marino find_omp_clause (tree clauses, enum omp_clause_code kind)
169e4b17023SJohn Marino {
170e4b17023SJohn Marino for (; clauses ; clauses = OMP_CLAUSE_CHAIN (clauses))
171e4b17023SJohn Marino if (OMP_CLAUSE_CODE (clauses) == kind)
172e4b17023SJohn Marino return clauses;
173e4b17023SJohn Marino
174e4b17023SJohn Marino return NULL_TREE;
175e4b17023SJohn Marino }
176e4b17023SJohn Marino
177e4b17023SJohn Marino /* Return true if CTX is for an omp parallel. */
178e4b17023SJohn Marino
179e4b17023SJohn Marino static inline bool
is_parallel_ctx(omp_context * ctx)180e4b17023SJohn Marino is_parallel_ctx (omp_context *ctx)
181e4b17023SJohn Marino {
182e4b17023SJohn Marino return gimple_code (ctx->stmt) == GIMPLE_OMP_PARALLEL;
183e4b17023SJohn Marino }
184e4b17023SJohn Marino
185e4b17023SJohn Marino
186e4b17023SJohn Marino /* Return true if CTX is for an omp task. */
187e4b17023SJohn Marino
188e4b17023SJohn Marino static inline bool
is_task_ctx(omp_context * ctx)189e4b17023SJohn Marino is_task_ctx (omp_context *ctx)
190e4b17023SJohn Marino {
191e4b17023SJohn Marino return gimple_code (ctx->stmt) == GIMPLE_OMP_TASK;
192e4b17023SJohn Marino }
193e4b17023SJohn Marino
194e4b17023SJohn Marino
195e4b17023SJohn Marino /* Return true if CTX is for an omp parallel or omp task. */
196e4b17023SJohn Marino
197e4b17023SJohn Marino static inline bool
is_taskreg_ctx(omp_context * ctx)198e4b17023SJohn Marino is_taskreg_ctx (omp_context *ctx)
199e4b17023SJohn Marino {
200e4b17023SJohn Marino return gimple_code (ctx->stmt) == GIMPLE_OMP_PARALLEL
201e4b17023SJohn Marino || gimple_code (ctx->stmt) == GIMPLE_OMP_TASK;
202e4b17023SJohn Marino }
203e4b17023SJohn Marino
204e4b17023SJohn Marino
205e4b17023SJohn Marino /* Return true if REGION is a combined parallel+workshare region. */
206e4b17023SJohn Marino
207e4b17023SJohn Marino static inline bool
is_combined_parallel(struct omp_region * region)208e4b17023SJohn Marino is_combined_parallel (struct omp_region *region)
209e4b17023SJohn Marino {
210e4b17023SJohn Marino return region->is_combined_parallel;
211e4b17023SJohn Marino }
212e4b17023SJohn Marino
213e4b17023SJohn Marino
214e4b17023SJohn Marino /* Extract the header elements of parallel loop FOR_STMT and store
215e4b17023SJohn Marino them into *FD. */
216e4b17023SJohn Marino
217e4b17023SJohn Marino static void
extract_omp_for_data(gimple for_stmt,struct omp_for_data * fd,struct omp_for_data_loop * loops)218e4b17023SJohn Marino extract_omp_for_data (gimple for_stmt, struct omp_for_data *fd,
219e4b17023SJohn Marino struct omp_for_data_loop *loops)
220e4b17023SJohn Marino {
221e4b17023SJohn Marino tree t, var, *collapse_iter, *collapse_count;
222e4b17023SJohn Marino tree count = NULL_TREE, iter_type = long_integer_type_node;
223e4b17023SJohn Marino struct omp_for_data_loop *loop;
224e4b17023SJohn Marino int i;
225e4b17023SJohn Marino struct omp_for_data_loop dummy_loop;
226e4b17023SJohn Marino location_t loc = gimple_location (for_stmt);
227e4b17023SJohn Marino
228e4b17023SJohn Marino fd->for_stmt = for_stmt;
229e4b17023SJohn Marino fd->pre = NULL;
230e4b17023SJohn Marino fd->collapse = gimple_omp_for_collapse (for_stmt);
231e4b17023SJohn Marino if (fd->collapse > 1)
232e4b17023SJohn Marino fd->loops = loops;
233e4b17023SJohn Marino else
234e4b17023SJohn Marino fd->loops = &fd->loop;
235e4b17023SJohn Marino
236e4b17023SJohn Marino fd->have_nowait = fd->have_ordered = false;
237e4b17023SJohn Marino fd->sched_kind = OMP_CLAUSE_SCHEDULE_STATIC;
238e4b17023SJohn Marino fd->chunk_size = NULL_TREE;
239e4b17023SJohn Marino collapse_iter = NULL;
240e4b17023SJohn Marino collapse_count = NULL;
241e4b17023SJohn Marino
242e4b17023SJohn Marino for (t = gimple_omp_for_clauses (for_stmt); t ; t = OMP_CLAUSE_CHAIN (t))
243e4b17023SJohn Marino switch (OMP_CLAUSE_CODE (t))
244e4b17023SJohn Marino {
245e4b17023SJohn Marino case OMP_CLAUSE_NOWAIT:
246e4b17023SJohn Marino fd->have_nowait = true;
247e4b17023SJohn Marino break;
248e4b17023SJohn Marino case OMP_CLAUSE_ORDERED:
249e4b17023SJohn Marino fd->have_ordered = true;
250e4b17023SJohn Marino break;
251e4b17023SJohn Marino case OMP_CLAUSE_SCHEDULE:
252e4b17023SJohn Marino fd->sched_kind = OMP_CLAUSE_SCHEDULE_KIND (t);
253e4b17023SJohn Marino fd->chunk_size = OMP_CLAUSE_SCHEDULE_CHUNK_EXPR (t);
254e4b17023SJohn Marino break;
255e4b17023SJohn Marino case OMP_CLAUSE_COLLAPSE:
256e4b17023SJohn Marino if (fd->collapse > 1)
257e4b17023SJohn Marino {
258e4b17023SJohn Marino collapse_iter = &OMP_CLAUSE_COLLAPSE_ITERVAR (t);
259e4b17023SJohn Marino collapse_count = &OMP_CLAUSE_COLLAPSE_COUNT (t);
260e4b17023SJohn Marino }
261e4b17023SJohn Marino default:
262e4b17023SJohn Marino break;
263e4b17023SJohn Marino }
264e4b17023SJohn Marino
265e4b17023SJohn Marino /* FIXME: for now map schedule(auto) to schedule(static).
266e4b17023SJohn Marino There should be analysis to determine whether all iterations
267e4b17023SJohn Marino are approximately the same amount of work (then schedule(static)
268e4b17023SJohn Marino is best) or if it varies (then schedule(dynamic,N) is better). */
269e4b17023SJohn Marino if (fd->sched_kind == OMP_CLAUSE_SCHEDULE_AUTO)
270e4b17023SJohn Marino {
271e4b17023SJohn Marino fd->sched_kind = OMP_CLAUSE_SCHEDULE_STATIC;
272e4b17023SJohn Marino gcc_assert (fd->chunk_size == NULL);
273e4b17023SJohn Marino }
274e4b17023SJohn Marino gcc_assert (fd->collapse == 1 || collapse_iter != NULL);
275e4b17023SJohn Marino if (fd->sched_kind == OMP_CLAUSE_SCHEDULE_RUNTIME)
276e4b17023SJohn Marino gcc_assert (fd->chunk_size == NULL);
277e4b17023SJohn Marino else if (fd->chunk_size == NULL)
278e4b17023SJohn Marino {
279e4b17023SJohn Marino /* We only need to compute a default chunk size for ordered
280e4b17023SJohn Marino static loops and dynamic loops. */
281e4b17023SJohn Marino if (fd->sched_kind != OMP_CLAUSE_SCHEDULE_STATIC
282e4b17023SJohn Marino || fd->have_ordered
283e4b17023SJohn Marino || fd->collapse > 1)
284e4b17023SJohn Marino fd->chunk_size = (fd->sched_kind == OMP_CLAUSE_SCHEDULE_STATIC)
285e4b17023SJohn Marino ? integer_zero_node : integer_one_node;
286e4b17023SJohn Marino }
287e4b17023SJohn Marino
288e4b17023SJohn Marino for (i = 0; i < fd->collapse; i++)
289e4b17023SJohn Marino {
290e4b17023SJohn Marino if (fd->collapse == 1)
291e4b17023SJohn Marino loop = &fd->loop;
292e4b17023SJohn Marino else if (loops != NULL)
293e4b17023SJohn Marino loop = loops + i;
294e4b17023SJohn Marino else
295e4b17023SJohn Marino loop = &dummy_loop;
296e4b17023SJohn Marino
297e4b17023SJohn Marino
298e4b17023SJohn Marino loop->v = gimple_omp_for_index (for_stmt, i);
299e4b17023SJohn Marino gcc_assert (SSA_VAR_P (loop->v));
300e4b17023SJohn Marino gcc_assert (TREE_CODE (TREE_TYPE (loop->v)) == INTEGER_TYPE
301e4b17023SJohn Marino || TREE_CODE (TREE_TYPE (loop->v)) == POINTER_TYPE);
302e4b17023SJohn Marino var = TREE_CODE (loop->v) == SSA_NAME ? SSA_NAME_VAR (loop->v) : loop->v;
303e4b17023SJohn Marino loop->n1 = gimple_omp_for_initial (for_stmt, i);
304e4b17023SJohn Marino
305e4b17023SJohn Marino loop->cond_code = gimple_omp_for_cond (for_stmt, i);
306e4b17023SJohn Marino loop->n2 = gimple_omp_for_final (for_stmt, i);
307e4b17023SJohn Marino switch (loop->cond_code)
308e4b17023SJohn Marino {
309e4b17023SJohn Marino case LT_EXPR:
310e4b17023SJohn Marino case GT_EXPR:
311e4b17023SJohn Marino break;
312e4b17023SJohn Marino case LE_EXPR:
313e4b17023SJohn Marino if (POINTER_TYPE_P (TREE_TYPE (loop->n2)))
314e4b17023SJohn Marino loop->n2 = fold_build_pointer_plus_hwi_loc (loc, loop->n2, 1);
315e4b17023SJohn Marino else
316e4b17023SJohn Marino loop->n2 = fold_build2_loc (loc,
317e4b17023SJohn Marino PLUS_EXPR, TREE_TYPE (loop->n2), loop->n2,
318e4b17023SJohn Marino build_int_cst (TREE_TYPE (loop->n2), 1));
319e4b17023SJohn Marino loop->cond_code = LT_EXPR;
320e4b17023SJohn Marino break;
321e4b17023SJohn Marino case GE_EXPR:
322e4b17023SJohn Marino if (POINTER_TYPE_P (TREE_TYPE (loop->n2)))
323e4b17023SJohn Marino loop->n2 = fold_build_pointer_plus_hwi_loc (loc, loop->n2, -1);
324e4b17023SJohn Marino else
325e4b17023SJohn Marino loop->n2 = fold_build2_loc (loc,
326e4b17023SJohn Marino MINUS_EXPR, TREE_TYPE (loop->n2), loop->n2,
327e4b17023SJohn Marino build_int_cst (TREE_TYPE (loop->n2), 1));
328e4b17023SJohn Marino loop->cond_code = GT_EXPR;
329e4b17023SJohn Marino break;
330e4b17023SJohn Marino default:
331e4b17023SJohn Marino gcc_unreachable ();
332e4b17023SJohn Marino }
333e4b17023SJohn Marino
334e4b17023SJohn Marino t = gimple_omp_for_incr (for_stmt, i);
335e4b17023SJohn Marino gcc_assert (TREE_OPERAND (t, 0) == var);
336e4b17023SJohn Marino switch (TREE_CODE (t))
337e4b17023SJohn Marino {
338e4b17023SJohn Marino case PLUS_EXPR:
339e4b17023SJohn Marino case POINTER_PLUS_EXPR:
340e4b17023SJohn Marino loop->step = TREE_OPERAND (t, 1);
341e4b17023SJohn Marino break;
342e4b17023SJohn Marino case MINUS_EXPR:
343e4b17023SJohn Marino loop->step = TREE_OPERAND (t, 1);
344e4b17023SJohn Marino loop->step = fold_build1_loc (loc,
345e4b17023SJohn Marino NEGATE_EXPR, TREE_TYPE (loop->step),
346e4b17023SJohn Marino loop->step);
347e4b17023SJohn Marino break;
348e4b17023SJohn Marino default:
349e4b17023SJohn Marino gcc_unreachable ();
350e4b17023SJohn Marino }
351e4b17023SJohn Marino
352e4b17023SJohn Marino if (iter_type != long_long_unsigned_type_node)
353e4b17023SJohn Marino {
354e4b17023SJohn Marino if (POINTER_TYPE_P (TREE_TYPE (loop->v)))
355e4b17023SJohn Marino iter_type = long_long_unsigned_type_node;
356e4b17023SJohn Marino else if (TYPE_UNSIGNED (TREE_TYPE (loop->v))
357e4b17023SJohn Marino && TYPE_PRECISION (TREE_TYPE (loop->v))
358e4b17023SJohn Marino >= TYPE_PRECISION (iter_type))
359e4b17023SJohn Marino {
360e4b17023SJohn Marino tree n;
361e4b17023SJohn Marino
362e4b17023SJohn Marino if (loop->cond_code == LT_EXPR)
363e4b17023SJohn Marino n = fold_build2_loc (loc,
364e4b17023SJohn Marino PLUS_EXPR, TREE_TYPE (loop->v),
365e4b17023SJohn Marino loop->n2, loop->step);
366e4b17023SJohn Marino else
367e4b17023SJohn Marino n = loop->n1;
368e4b17023SJohn Marino if (TREE_CODE (n) != INTEGER_CST
369e4b17023SJohn Marino || tree_int_cst_lt (TYPE_MAX_VALUE (iter_type), n))
370e4b17023SJohn Marino iter_type = long_long_unsigned_type_node;
371e4b17023SJohn Marino }
372e4b17023SJohn Marino else if (TYPE_PRECISION (TREE_TYPE (loop->v))
373e4b17023SJohn Marino > TYPE_PRECISION (iter_type))
374e4b17023SJohn Marino {
375e4b17023SJohn Marino tree n1, n2;
376e4b17023SJohn Marino
377e4b17023SJohn Marino if (loop->cond_code == LT_EXPR)
378e4b17023SJohn Marino {
379e4b17023SJohn Marino n1 = loop->n1;
380e4b17023SJohn Marino n2 = fold_build2_loc (loc,
381e4b17023SJohn Marino PLUS_EXPR, TREE_TYPE (loop->v),
382e4b17023SJohn Marino loop->n2, loop->step);
383e4b17023SJohn Marino }
384e4b17023SJohn Marino else
385e4b17023SJohn Marino {
386e4b17023SJohn Marino n1 = fold_build2_loc (loc,
387e4b17023SJohn Marino MINUS_EXPR, TREE_TYPE (loop->v),
388e4b17023SJohn Marino loop->n2, loop->step);
389e4b17023SJohn Marino n2 = loop->n1;
390e4b17023SJohn Marino }
391e4b17023SJohn Marino if (TREE_CODE (n1) != INTEGER_CST
392e4b17023SJohn Marino || TREE_CODE (n2) != INTEGER_CST
393e4b17023SJohn Marino || !tree_int_cst_lt (TYPE_MIN_VALUE (iter_type), n1)
394e4b17023SJohn Marino || !tree_int_cst_lt (n2, TYPE_MAX_VALUE (iter_type)))
395e4b17023SJohn Marino iter_type = long_long_unsigned_type_node;
396e4b17023SJohn Marino }
397e4b17023SJohn Marino }
398e4b17023SJohn Marino
399e4b17023SJohn Marino if (collapse_count && *collapse_count == NULL)
400e4b17023SJohn Marino {
401e4b17023SJohn Marino if ((i == 0 || count != NULL_TREE)
402e4b17023SJohn Marino && TREE_CODE (TREE_TYPE (loop->v)) == INTEGER_TYPE
403e4b17023SJohn Marino && TREE_CONSTANT (loop->n1)
404e4b17023SJohn Marino && TREE_CONSTANT (loop->n2)
405e4b17023SJohn Marino && TREE_CODE (loop->step) == INTEGER_CST)
406e4b17023SJohn Marino {
407e4b17023SJohn Marino tree itype = TREE_TYPE (loop->v);
408e4b17023SJohn Marino
409e4b17023SJohn Marino if (POINTER_TYPE_P (itype))
410e4b17023SJohn Marino itype
411e4b17023SJohn Marino = lang_hooks.types.type_for_size (TYPE_PRECISION (itype), 0);
412e4b17023SJohn Marino t = build_int_cst (itype, (loop->cond_code == LT_EXPR ? -1 : 1));
413e4b17023SJohn Marino t = fold_build2_loc (loc,
414e4b17023SJohn Marino PLUS_EXPR, itype,
415e4b17023SJohn Marino fold_convert_loc (loc, itype, loop->step), t);
416e4b17023SJohn Marino t = fold_build2_loc (loc, PLUS_EXPR, itype, t,
417e4b17023SJohn Marino fold_convert_loc (loc, itype, loop->n2));
418e4b17023SJohn Marino t = fold_build2_loc (loc, MINUS_EXPR, itype, t,
419e4b17023SJohn Marino fold_convert_loc (loc, itype, loop->n1));
420e4b17023SJohn Marino if (TYPE_UNSIGNED (itype) && loop->cond_code == GT_EXPR)
421e4b17023SJohn Marino t = fold_build2_loc (loc, TRUNC_DIV_EXPR, itype,
422e4b17023SJohn Marino fold_build1_loc (loc, NEGATE_EXPR, itype, t),
423e4b17023SJohn Marino fold_build1_loc (loc, NEGATE_EXPR, itype,
424e4b17023SJohn Marino fold_convert_loc (loc, itype,
425e4b17023SJohn Marino loop->step)));
426e4b17023SJohn Marino else
427e4b17023SJohn Marino t = fold_build2_loc (loc, TRUNC_DIV_EXPR, itype, t,
428e4b17023SJohn Marino fold_convert_loc (loc, itype, loop->step));
429e4b17023SJohn Marino t = fold_convert_loc (loc, long_long_unsigned_type_node, t);
430e4b17023SJohn Marino if (count != NULL_TREE)
431e4b17023SJohn Marino count = fold_build2_loc (loc,
432e4b17023SJohn Marino MULT_EXPR, long_long_unsigned_type_node,
433e4b17023SJohn Marino count, t);
434e4b17023SJohn Marino else
435e4b17023SJohn Marino count = t;
436e4b17023SJohn Marino if (TREE_CODE (count) != INTEGER_CST)
437e4b17023SJohn Marino count = NULL_TREE;
438e4b17023SJohn Marino }
439e4b17023SJohn Marino else
440e4b17023SJohn Marino count = NULL_TREE;
441e4b17023SJohn Marino }
442e4b17023SJohn Marino }
443e4b17023SJohn Marino
444e4b17023SJohn Marino if (count)
445e4b17023SJohn Marino {
446e4b17023SJohn Marino if (!tree_int_cst_lt (count, TYPE_MAX_VALUE (long_integer_type_node)))
447e4b17023SJohn Marino iter_type = long_long_unsigned_type_node;
448e4b17023SJohn Marino else
449e4b17023SJohn Marino iter_type = long_integer_type_node;
450e4b17023SJohn Marino }
451e4b17023SJohn Marino else if (collapse_iter && *collapse_iter != NULL)
452e4b17023SJohn Marino iter_type = TREE_TYPE (*collapse_iter);
453e4b17023SJohn Marino fd->iter_type = iter_type;
454e4b17023SJohn Marino if (collapse_iter && *collapse_iter == NULL)
455e4b17023SJohn Marino *collapse_iter = create_tmp_var (iter_type, ".iter");
456e4b17023SJohn Marino if (collapse_count && *collapse_count == NULL)
457e4b17023SJohn Marino {
458e4b17023SJohn Marino if (count)
459e4b17023SJohn Marino *collapse_count = fold_convert_loc (loc, iter_type, count);
460e4b17023SJohn Marino else
461e4b17023SJohn Marino *collapse_count = create_tmp_var (iter_type, ".count");
462e4b17023SJohn Marino }
463e4b17023SJohn Marino
464e4b17023SJohn Marino if (fd->collapse > 1)
465e4b17023SJohn Marino {
466e4b17023SJohn Marino fd->loop.v = *collapse_iter;
467e4b17023SJohn Marino fd->loop.n1 = build_int_cst (TREE_TYPE (fd->loop.v), 0);
468e4b17023SJohn Marino fd->loop.n2 = *collapse_count;
469e4b17023SJohn Marino fd->loop.step = build_int_cst (TREE_TYPE (fd->loop.v), 1);
470e4b17023SJohn Marino fd->loop.cond_code = LT_EXPR;
471e4b17023SJohn Marino }
472e4b17023SJohn Marino }
473e4b17023SJohn Marino
474e4b17023SJohn Marino
475e4b17023SJohn Marino /* Given two blocks PAR_ENTRY_BB and WS_ENTRY_BB such that WS_ENTRY_BB
476e4b17023SJohn Marino is the immediate dominator of PAR_ENTRY_BB, return true if there
477e4b17023SJohn Marino are no data dependencies that would prevent expanding the parallel
478e4b17023SJohn Marino directive at PAR_ENTRY_BB as a combined parallel+workshare region.
479e4b17023SJohn Marino
480e4b17023SJohn Marino When expanding a combined parallel+workshare region, the call to
481e4b17023SJohn Marino the child function may need additional arguments in the case of
482e4b17023SJohn Marino GIMPLE_OMP_FOR regions. In some cases, these arguments are
483e4b17023SJohn Marino computed out of variables passed in from the parent to the child
484e4b17023SJohn Marino via 'struct .omp_data_s'. For instance:
485e4b17023SJohn Marino
486e4b17023SJohn Marino #pragma omp parallel for schedule (guided, i * 4)
487e4b17023SJohn Marino for (j ...)
488e4b17023SJohn Marino
489e4b17023SJohn Marino Is lowered into:
490e4b17023SJohn Marino
491e4b17023SJohn Marino # BLOCK 2 (PAR_ENTRY_BB)
492e4b17023SJohn Marino .omp_data_o.i = i;
493e4b17023SJohn Marino #pragma omp parallel [child fn: bar.omp_fn.0 ( ..., D.1598)
494e4b17023SJohn Marino
495e4b17023SJohn Marino # BLOCK 3 (WS_ENTRY_BB)
496e4b17023SJohn Marino .omp_data_i = &.omp_data_o;
497e4b17023SJohn Marino D.1667 = .omp_data_i->i;
498e4b17023SJohn Marino D.1598 = D.1667 * 4;
499e4b17023SJohn Marino #pragma omp for schedule (guided, D.1598)
500e4b17023SJohn Marino
501e4b17023SJohn Marino When we outline the parallel region, the call to the child function
502e4b17023SJohn Marino 'bar.omp_fn.0' will need the value D.1598 in its argument list, but
503e4b17023SJohn Marino that value is computed *after* the call site. So, in principle we
504e4b17023SJohn Marino cannot do the transformation.
505e4b17023SJohn Marino
506e4b17023SJohn Marino To see whether the code in WS_ENTRY_BB blocks the combined
507e4b17023SJohn Marino parallel+workshare call, we collect all the variables used in the
508e4b17023SJohn Marino GIMPLE_OMP_FOR header check whether they appear on the LHS of any
509e4b17023SJohn Marino statement in WS_ENTRY_BB. If so, then we cannot emit the combined
510e4b17023SJohn Marino call.
511e4b17023SJohn Marino
512e4b17023SJohn Marino FIXME. If we had the SSA form built at this point, we could merely
513e4b17023SJohn Marino hoist the code in block 3 into block 2 and be done with it. But at
514e4b17023SJohn Marino this point we don't have dataflow information and though we could
515e4b17023SJohn Marino hack something up here, it is really not worth the aggravation. */
516e4b17023SJohn Marino
517e4b17023SJohn Marino static bool
workshare_safe_to_combine_p(basic_block ws_entry_bb)518e4b17023SJohn Marino workshare_safe_to_combine_p (basic_block ws_entry_bb)
519e4b17023SJohn Marino {
520e4b17023SJohn Marino struct omp_for_data fd;
521e4b17023SJohn Marino gimple ws_stmt = last_stmt (ws_entry_bb);
522e4b17023SJohn Marino
523e4b17023SJohn Marino if (gimple_code (ws_stmt) == GIMPLE_OMP_SECTIONS)
524e4b17023SJohn Marino return true;
525e4b17023SJohn Marino
526e4b17023SJohn Marino gcc_assert (gimple_code (ws_stmt) == GIMPLE_OMP_FOR);
527e4b17023SJohn Marino
528e4b17023SJohn Marino extract_omp_for_data (ws_stmt, &fd, NULL);
529e4b17023SJohn Marino
530e4b17023SJohn Marino if (fd.collapse > 1 && TREE_CODE (fd.loop.n2) != INTEGER_CST)
531e4b17023SJohn Marino return false;
532e4b17023SJohn Marino if (fd.iter_type != long_integer_type_node)
533e4b17023SJohn Marino return false;
534e4b17023SJohn Marino
535e4b17023SJohn Marino /* FIXME. We give up too easily here. If any of these arguments
536e4b17023SJohn Marino are not constants, they will likely involve variables that have
537e4b17023SJohn Marino been mapped into fields of .omp_data_s for sharing with the child
538e4b17023SJohn Marino function. With appropriate data flow, it would be possible to
539e4b17023SJohn Marino see through this. */
540e4b17023SJohn Marino if (!is_gimple_min_invariant (fd.loop.n1)
541e4b17023SJohn Marino || !is_gimple_min_invariant (fd.loop.n2)
542e4b17023SJohn Marino || !is_gimple_min_invariant (fd.loop.step)
543e4b17023SJohn Marino || (fd.chunk_size && !is_gimple_min_invariant (fd.chunk_size)))
544e4b17023SJohn Marino return false;
545e4b17023SJohn Marino
546e4b17023SJohn Marino return true;
547e4b17023SJohn Marino }
548e4b17023SJohn Marino
549e4b17023SJohn Marino
550e4b17023SJohn Marino /* Collect additional arguments needed to emit a combined
551e4b17023SJohn Marino parallel+workshare call. WS_STMT is the workshare directive being
552e4b17023SJohn Marino expanded. */
553e4b17023SJohn Marino
VEC(tree,gc)554e4b17023SJohn Marino static VEC(tree,gc) *
555e4b17023SJohn Marino get_ws_args_for (gimple ws_stmt)
556e4b17023SJohn Marino {
557e4b17023SJohn Marino tree t;
558e4b17023SJohn Marino location_t loc = gimple_location (ws_stmt);
559e4b17023SJohn Marino VEC(tree,gc) *ws_args;
560e4b17023SJohn Marino
561e4b17023SJohn Marino if (gimple_code (ws_stmt) == GIMPLE_OMP_FOR)
562e4b17023SJohn Marino {
563e4b17023SJohn Marino struct omp_for_data fd;
564e4b17023SJohn Marino
565e4b17023SJohn Marino extract_omp_for_data (ws_stmt, &fd, NULL);
566e4b17023SJohn Marino
567e4b17023SJohn Marino ws_args = VEC_alloc (tree, gc, 3 + (fd.chunk_size != 0));
568e4b17023SJohn Marino
569e4b17023SJohn Marino t = fold_convert_loc (loc, long_integer_type_node, fd.loop.n1);
570e4b17023SJohn Marino VEC_quick_push (tree, ws_args, t);
571e4b17023SJohn Marino
572e4b17023SJohn Marino t = fold_convert_loc (loc, long_integer_type_node, fd.loop.n2);
573e4b17023SJohn Marino VEC_quick_push (tree, ws_args, t);
574e4b17023SJohn Marino
575e4b17023SJohn Marino t = fold_convert_loc (loc, long_integer_type_node, fd.loop.step);
576e4b17023SJohn Marino VEC_quick_push (tree, ws_args, t);
577e4b17023SJohn Marino
578e4b17023SJohn Marino if (fd.chunk_size)
579e4b17023SJohn Marino {
580e4b17023SJohn Marino t = fold_convert_loc (loc, long_integer_type_node, fd.chunk_size);
581e4b17023SJohn Marino VEC_quick_push (tree, ws_args, t);
582e4b17023SJohn Marino }
583e4b17023SJohn Marino
584e4b17023SJohn Marino return ws_args;
585e4b17023SJohn Marino }
586e4b17023SJohn Marino else if (gimple_code (ws_stmt) == GIMPLE_OMP_SECTIONS)
587e4b17023SJohn Marino {
588e4b17023SJohn Marino /* Number of sections is equal to the number of edges from the
589e4b17023SJohn Marino GIMPLE_OMP_SECTIONS_SWITCH statement, except for the one to
590e4b17023SJohn Marino the exit of the sections region. */
591e4b17023SJohn Marino basic_block bb = single_succ (gimple_bb (ws_stmt));
592e4b17023SJohn Marino t = build_int_cst (unsigned_type_node, EDGE_COUNT (bb->succs) - 1);
593e4b17023SJohn Marino ws_args = VEC_alloc (tree, gc, 1);
594e4b17023SJohn Marino VEC_quick_push (tree, ws_args, t);
595e4b17023SJohn Marino return ws_args;
596e4b17023SJohn Marino }
597e4b17023SJohn Marino
598e4b17023SJohn Marino gcc_unreachable ();
599e4b17023SJohn Marino }
600e4b17023SJohn Marino
601e4b17023SJohn Marino
602e4b17023SJohn Marino /* Discover whether REGION is a combined parallel+workshare region. */
603e4b17023SJohn Marino
604e4b17023SJohn Marino static void
determine_parallel_type(struct omp_region * region)605e4b17023SJohn Marino determine_parallel_type (struct omp_region *region)
606e4b17023SJohn Marino {
607e4b17023SJohn Marino basic_block par_entry_bb, par_exit_bb;
608e4b17023SJohn Marino basic_block ws_entry_bb, ws_exit_bb;
609e4b17023SJohn Marino
610e4b17023SJohn Marino if (region == NULL || region->inner == NULL
611e4b17023SJohn Marino || region->exit == NULL || region->inner->exit == NULL
612e4b17023SJohn Marino || region->inner->cont == NULL)
613e4b17023SJohn Marino return;
614e4b17023SJohn Marino
615e4b17023SJohn Marino /* We only support parallel+for and parallel+sections. */
616e4b17023SJohn Marino if (region->type != GIMPLE_OMP_PARALLEL
617e4b17023SJohn Marino || (region->inner->type != GIMPLE_OMP_FOR
618e4b17023SJohn Marino && region->inner->type != GIMPLE_OMP_SECTIONS))
619e4b17023SJohn Marino return;
620e4b17023SJohn Marino
621e4b17023SJohn Marino /* Check for perfect nesting PAR_ENTRY_BB -> WS_ENTRY_BB and
622e4b17023SJohn Marino WS_EXIT_BB -> PAR_EXIT_BB. */
623e4b17023SJohn Marino par_entry_bb = region->entry;
624e4b17023SJohn Marino par_exit_bb = region->exit;
625e4b17023SJohn Marino ws_entry_bb = region->inner->entry;
626e4b17023SJohn Marino ws_exit_bb = region->inner->exit;
627e4b17023SJohn Marino
628e4b17023SJohn Marino if (single_succ (par_entry_bb) == ws_entry_bb
629e4b17023SJohn Marino && single_succ (ws_exit_bb) == par_exit_bb
630e4b17023SJohn Marino && workshare_safe_to_combine_p (ws_entry_bb)
631e4b17023SJohn Marino && (gimple_omp_parallel_combined_p (last_stmt (par_entry_bb))
632e4b17023SJohn Marino || (last_and_only_stmt (ws_entry_bb)
633e4b17023SJohn Marino && last_and_only_stmt (par_exit_bb))))
634e4b17023SJohn Marino {
635e4b17023SJohn Marino gimple ws_stmt = last_stmt (ws_entry_bb);
636e4b17023SJohn Marino
637e4b17023SJohn Marino if (region->inner->type == GIMPLE_OMP_FOR)
638e4b17023SJohn Marino {
639e4b17023SJohn Marino /* If this is a combined parallel loop, we need to determine
640e4b17023SJohn Marino whether or not to use the combined library calls. There
641e4b17023SJohn Marino are two cases where we do not apply the transformation:
642e4b17023SJohn Marino static loops and any kind of ordered loop. In the first
643e4b17023SJohn Marino case, we already open code the loop so there is no need
644e4b17023SJohn Marino to do anything else. In the latter case, the combined
645e4b17023SJohn Marino parallel loop call would still need extra synchronization
646e4b17023SJohn Marino to implement ordered semantics, so there would not be any
647e4b17023SJohn Marino gain in using the combined call. */
648e4b17023SJohn Marino tree clauses = gimple_omp_for_clauses (ws_stmt);
649e4b17023SJohn Marino tree c = find_omp_clause (clauses, OMP_CLAUSE_SCHEDULE);
650e4b17023SJohn Marino if (c == NULL
651e4b17023SJohn Marino || OMP_CLAUSE_SCHEDULE_KIND (c) == OMP_CLAUSE_SCHEDULE_STATIC
652e4b17023SJohn Marino || find_omp_clause (clauses, OMP_CLAUSE_ORDERED))
653e4b17023SJohn Marino {
654e4b17023SJohn Marino region->is_combined_parallel = false;
655e4b17023SJohn Marino region->inner->is_combined_parallel = false;
656e4b17023SJohn Marino return;
657e4b17023SJohn Marino }
658e4b17023SJohn Marino }
659e4b17023SJohn Marino
660e4b17023SJohn Marino region->is_combined_parallel = true;
661e4b17023SJohn Marino region->inner->is_combined_parallel = true;
662e4b17023SJohn Marino region->ws_args = get_ws_args_for (ws_stmt);
663e4b17023SJohn Marino }
664e4b17023SJohn Marino }
665e4b17023SJohn Marino
666e4b17023SJohn Marino
667e4b17023SJohn Marino /* Return true if EXPR is variable sized. */
668e4b17023SJohn Marino
669e4b17023SJohn Marino static inline bool
is_variable_sized(const_tree expr)670e4b17023SJohn Marino is_variable_sized (const_tree expr)
671e4b17023SJohn Marino {
672e4b17023SJohn Marino return !TREE_CONSTANT (TYPE_SIZE_UNIT (TREE_TYPE (expr)));
673e4b17023SJohn Marino }
674e4b17023SJohn Marino
675e4b17023SJohn Marino /* Return true if DECL is a reference type. */
676e4b17023SJohn Marino
677e4b17023SJohn Marino static inline bool
is_reference(tree decl)678e4b17023SJohn Marino is_reference (tree decl)
679e4b17023SJohn Marino {
680e4b17023SJohn Marino return lang_hooks.decls.omp_privatize_by_reference (decl);
681e4b17023SJohn Marino }
682e4b17023SJohn Marino
683e4b17023SJohn Marino /* Lookup variables in the decl or field splay trees. The "maybe" form
684e4b17023SJohn Marino allows for the variable form to not have been entered, otherwise we
685e4b17023SJohn Marino assert that the variable must have been entered. */
686e4b17023SJohn Marino
687e4b17023SJohn Marino static inline tree
lookup_decl(tree var,omp_context * ctx)688e4b17023SJohn Marino lookup_decl (tree var, omp_context *ctx)
689e4b17023SJohn Marino {
690e4b17023SJohn Marino tree *n;
691e4b17023SJohn Marino n = (tree *) pointer_map_contains (ctx->cb.decl_map, var);
692e4b17023SJohn Marino return *n;
693e4b17023SJohn Marino }
694e4b17023SJohn Marino
695e4b17023SJohn Marino static inline tree
maybe_lookup_decl(const_tree var,omp_context * ctx)696e4b17023SJohn Marino maybe_lookup_decl (const_tree var, omp_context *ctx)
697e4b17023SJohn Marino {
698e4b17023SJohn Marino tree *n;
699e4b17023SJohn Marino n = (tree *) pointer_map_contains (ctx->cb.decl_map, var);
700e4b17023SJohn Marino return n ? *n : NULL_TREE;
701e4b17023SJohn Marino }
702e4b17023SJohn Marino
703e4b17023SJohn Marino static inline tree
lookup_field(tree var,omp_context * ctx)704e4b17023SJohn Marino lookup_field (tree var, omp_context *ctx)
705e4b17023SJohn Marino {
706e4b17023SJohn Marino splay_tree_node n;
707e4b17023SJohn Marino n = splay_tree_lookup (ctx->field_map, (splay_tree_key) var);
708e4b17023SJohn Marino return (tree) n->value;
709e4b17023SJohn Marino }
710e4b17023SJohn Marino
711e4b17023SJohn Marino static inline tree
lookup_sfield(tree var,omp_context * ctx)712e4b17023SJohn Marino lookup_sfield (tree var, omp_context *ctx)
713e4b17023SJohn Marino {
714e4b17023SJohn Marino splay_tree_node n;
715e4b17023SJohn Marino n = splay_tree_lookup (ctx->sfield_map
716e4b17023SJohn Marino ? ctx->sfield_map : ctx->field_map,
717e4b17023SJohn Marino (splay_tree_key) var);
718e4b17023SJohn Marino return (tree) n->value;
719e4b17023SJohn Marino }
720e4b17023SJohn Marino
721e4b17023SJohn Marino static inline tree
maybe_lookup_field(tree var,omp_context * ctx)722e4b17023SJohn Marino maybe_lookup_field (tree var, omp_context *ctx)
723e4b17023SJohn Marino {
724e4b17023SJohn Marino splay_tree_node n;
725e4b17023SJohn Marino n = splay_tree_lookup (ctx->field_map, (splay_tree_key) var);
726e4b17023SJohn Marino return n ? (tree) n->value : NULL_TREE;
727e4b17023SJohn Marino }
728e4b17023SJohn Marino
729e4b17023SJohn Marino /* Return true if DECL should be copied by pointer. SHARED_CTX is
730e4b17023SJohn Marino the parallel context if DECL is to be shared. */
731e4b17023SJohn Marino
732e4b17023SJohn Marino static bool
use_pointer_for_field(tree decl,omp_context * shared_ctx)733e4b17023SJohn Marino use_pointer_for_field (tree decl, omp_context *shared_ctx)
734e4b17023SJohn Marino {
735e4b17023SJohn Marino if (AGGREGATE_TYPE_P (TREE_TYPE (decl)))
736e4b17023SJohn Marino return true;
737e4b17023SJohn Marino
738e4b17023SJohn Marino /* We can only use copy-in/copy-out semantics for shared variables
739e4b17023SJohn Marino when we know the value is not accessible from an outer scope. */
740e4b17023SJohn Marino if (shared_ctx)
741e4b17023SJohn Marino {
742e4b17023SJohn Marino /* ??? Trivially accessible from anywhere. But why would we even
743e4b17023SJohn Marino be passing an address in this case? Should we simply assert
744e4b17023SJohn Marino this to be false, or should we have a cleanup pass that removes
745e4b17023SJohn Marino these from the list of mappings? */
746e4b17023SJohn Marino if (TREE_STATIC (decl) || DECL_EXTERNAL (decl))
747e4b17023SJohn Marino return true;
748e4b17023SJohn Marino
749e4b17023SJohn Marino /* For variables with DECL_HAS_VALUE_EXPR_P set, we cannot tell
750e4b17023SJohn Marino without analyzing the expression whether or not its location
751e4b17023SJohn Marino is accessible to anyone else. In the case of nested parallel
752e4b17023SJohn Marino regions it certainly may be. */
753e4b17023SJohn Marino if (TREE_CODE (decl) != RESULT_DECL && DECL_HAS_VALUE_EXPR_P (decl))
754e4b17023SJohn Marino return true;
755e4b17023SJohn Marino
756e4b17023SJohn Marino /* Do not use copy-in/copy-out for variables that have their
757e4b17023SJohn Marino address taken. */
758e4b17023SJohn Marino if (TREE_ADDRESSABLE (decl))
759e4b17023SJohn Marino return true;
760e4b17023SJohn Marino
761*5ce9237cSJohn Marino /* lower_send_shared_vars only uses copy-in, but not copy-out
762*5ce9237cSJohn Marino for these. */
763*5ce9237cSJohn Marino if (TREE_READONLY (decl)
764*5ce9237cSJohn Marino || ((TREE_CODE (decl) == RESULT_DECL
765*5ce9237cSJohn Marino || TREE_CODE (decl) == PARM_DECL)
766*5ce9237cSJohn Marino && DECL_BY_REFERENCE (decl)))
767*5ce9237cSJohn Marino return false;
768*5ce9237cSJohn Marino
769e4b17023SJohn Marino /* Disallow copy-in/out in nested parallel if
770e4b17023SJohn Marino decl is shared in outer parallel, otherwise
771e4b17023SJohn Marino each thread could store the shared variable
772e4b17023SJohn Marino in its own copy-in location, making the
773e4b17023SJohn Marino variable no longer really shared. */
774*5ce9237cSJohn Marino if (shared_ctx->is_nested)
775e4b17023SJohn Marino {
776e4b17023SJohn Marino omp_context *up;
777e4b17023SJohn Marino
778e4b17023SJohn Marino for (up = shared_ctx->outer; up; up = up->outer)
779e4b17023SJohn Marino if (is_taskreg_ctx (up) && maybe_lookup_decl (decl, up))
780e4b17023SJohn Marino break;
781e4b17023SJohn Marino
782e4b17023SJohn Marino if (up)
783e4b17023SJohn Marino {
784e4b17023SJohn Marino tree c;
785e4b17023SJohn Marino
786e4b17023SJohn Marino for (c = gimple_omp_taskreg_clauses (up->stmt);
787e4b17023SJohn Marino c; c = OMP_CLAUSE_CHAIN (c))
788e4b17023SJohn Marino if (OMP_CLAUSE_CODE (c) == OMP_CLAUSE_SHARED
789e4b17023SJohn Marino && OMP_CLAUSE_DECL (c) == decl)
790e4b17023SJohn Marino break;
791e4b17023SJohn Marino
792e4b17023SJohn Marino if (c)
793e4b17023SJohn Marino goto maybe_mark_addressable_and_ret;
794e4b17023SJohn Marino }
795e4b17023SJohn Marino }
796e4b17023SJohn Marino
797*5ce9237cSJohn Marino /* For tasks avoid using copy-in/out. As tasks can be
798e4b17023SJohn Marino deferred or executed in different thread, when GOMP_task
799e4b17023SJohn Marino returns, the task hasn't necessarily terminated. */
800*5ce9237cSJohn Marino if (is_task_ctx (shared_ctx))
801e4b17023SJohn Marino {
802e4b17023SJohn Marino tree outer;
803e4b17023SJohn Marino maybe_mark_addressable_and_ret:
804e4b17023SJohn Marino outer = maybe_lookup_decl_in_outer_ctx (decl, shared_ctx);
805e4b17023SJohn Marino if (is_gimple_reg (outer))
806e4b17023SJohn Marino {
807e4b17023SJohn Marino /* Taking address of OUTER in lower_send_shared_vars
808e4b17023SJohn Marino might need regimplification of everything that uses the
809e4b17023SJohn Marino variable. */
810e4b17023SJohn Marino if (!task_shared_vars)
811e4b17023SJohn Marino task_shared_vars = BITMAP_ALLOC (NULL);
812e4b17023SJohn Marino bitmap_set_bit (task_shared_vars, DECL_UID (outer));
813e4b17023SJohn Marino TREE_ADDRESSABLE (outer) = 1;
814e4b17023SJohn Marino }
815e4b17023SJohn Marino return true;
816e4b17023SJohn Marino }
817e4b17023SJohn Marino }
818e4b17023SJohn Marino
819e4b17023SJohn Marino return false;
820e4b17023SJohn Marino }
821e4b17023SJohn Marino
822e4b17023SJohn Marino /* Create a new VAR_DECL and copy information from VAR to it. */
823e4b17023SJohn Marino
824e4b17023SJohn Marino tree
copy_var_decl(tree var,tree name,tree type)825e4b17023SJohn Marino copy_var_decl (tree var, tree name, tree type)
826e4b17023SJohn Marino {
827e4b17023SJohn Marino tree copy = build_decl (DECL_SOURCE_LOCATION (var), VAR_DECL, name, type);
828e4b17023SJohn Marino
829e4b17023SJohn Marino TREE_ADDRESSABLE (copy) = TREE_ADDRESSABLE (var);
830e4b17023SJohn Marino TREE_THIS_VOLATILE (copy) = TREE_THIS_VOLATILE (var);
831e4b17023SJohn Marino DECL_GIMPLE_REG_P (copy) = DECL_GIMPLE_REG_P (var);
832e4b17023SJohn Marino DECL_ARTIFICIAL (copy) = DECL_ARTIFICIAL (var);
833e4b17023SJohn Marino DECL_IGNORED_P (copy) = DECL_IGNORED_P (var);
834e4b17023SJohn Marino DECL_CONTEXT (copy) = DECL_CONTEXT (var);
835e4b17023SJohn Marino TREE_USED (copy) = 1;
836e4b17023SJohn Marino DECL_SEEN_IN_BIND_EXPR_P (copy) = 1;
837e4b17023SJohn Marino
838e4b17023SJohn Marino return copy;
839e4b17023SJohn Marino }
840e4b17023SJohn Marino
841e4b17023SJohn Marino /* Construct a new automatic decl similar to VAR. */
842e4b17023SJohn Marino
843e4b17023SJohn Marino static tree
omp_copy_decl_2(tree var,tree name,tree type,omp_context * ctx)844e4b17023SJohn Marino omp_copy_decl_2 (tree var, tree name, tree type, omp_context *ctx)
845e4b17023SJohn Marino {
846e4b17023SJohn Marino tree copy = copy_var_decl (var, name, type);
847e4b17023SJohn Marino
848e4b17023SJohn Marino DECL_CONTEXT (copy) = current_function_decl;
849e4b17023SJohn Marino DECL_CHAIN (copy) = ctx->block_vars;
850e4b17023SJohn Marino ctx->block_vars = copy;
851e4b17023SJohn Marino
852e4b17023SJohn Marino return copy;
853e4b17023SJohn Marino }
854e4b17023SJohn Marino
855e4b17023SJohn Marino static tree
omp_copy_decl_1(tree var,omp_context * ctx)856e4b17023SJohn Marino omp_copy_decl_1 (tree var, omp_context *ctx)
857e4b17023SJohn Marino {
858e4b17023SJohn Marino return omp_copy_decl_2 (var, DECL_NAME (var), TREE_TYPE (var), ctx);
859e4b17023SJohn Marino }
860e4b17023SJohn Marino
861e4b17023SJohn Marino /* Build COMPONENT_REF and set TREE_THIS_VOLATILE and TREE_READONLY on it
862e4b17023SJohn Marino as appropriate. */
863e4b17023SJohn Marino static tree
omp_build_component_ref(tree obj,tree field)864e4b17023SJohn Marino omp_build_component_ref (tree obj, tree field)
865e4b17023SJohn Marino {
866e4b17023SJohn Marino tree ret = build3 (COMPONENT_REF, TREE_TYPE (field), obj, field, NULL);
867e4b17023SJohn Marino if (TREE_THIS_VOLATILE (field))
868e4b17023SJohn Marino TREE_THIS_VOLATILE (ret) |= 1;
869e4b17023SJohn Marino if (TREE_READONLY (field))
870e4b17023SJohn Marino TREE_READONLY (ret) |= 1;
871e4b17023SJohn Marino return ret;
872e4b17023SJohn Marino }
873e4b17023SJohn Marino
874e4b17023SJohn Marino /* Build tree nodes to access the field for VAR on the receiver side. */
875e4b17023SJohn Marino
876e4b17023SJohn Marino static tree
build_receiver_ref(tree var,bool by_ref,omp_context * ctx)877e4b17023SJohn Marino build_receiver_ref (tree var, bool by_ref, omp_context *ctx)
878e4b17023SJohn Marino {
879e4b17023SJohn Marino tree x, field = lookup_field (var, ctx);
880e4b17023SJohn Marino
881e4b17023SJohn Marino /* If the receiver record type was remapped in the child function,
882e4b17023SJohn Marino remap the field into the new record type. */
883e4b17023SJohn Marino x = maybe_lookup_field (field, ctx);
884e4b17023SJohn Marino if (x != NULL)
885e4b17023SJohn Marino field = x;
886e4b17023SJohn Marino
887e4b17023SJohn Marino x = build_simple_mem_ref (ctx->receiver_decl);
888e4b17023SJohn Marino x = omp_build_component_ref (x, field);
889e4b17023SJohn Marino if (by_ref)
890e4b17023SJohn Marino x = build_simple_mem_ref (x);
891e4b17023SJohn Marino
892e4b17023SJohn Marino return x;
893e4b17023SJohn Marino }
894e4b17023SJohn Marino
895e4b17023SJohn Marino /* Build tree nodes to access VAR in the scope outer to CTX. In the case
896e4b17023SJohn Marino of a parallel, this is a component reference; for workshare constructs
897e4b17023SJohn Marino this is some variable. */
898e4b17023SJohn Marino
899e4b17023SJohn Marino static tree
build_outer_var_ref(tree var,omp_context * ctx)900e4b17023SJohn Marino build_outer_var_ref (tree var, omp_context *ctx)
901e4b17023SJohn Marino {
902e4b17023SJohn Marino tree x;
903e4b17023SJohn Marino
904e4b17023SJohn Marino if (is_global_var (maybe_lookup_decl_in_outer_ctx (var, ctx)))
905e4b17023SJohn Marino x = var;
906e4b17023SJohn Marino else if (is_variable_sized (var))
907e4b17023SJohn Marino {
908e4b17023SJohn Marino x = TREE_OPERAND (DECL_VALUE_EXPR (var), 0);
909e4b17023SJohn Marino x = build_outer_var_ref (x, ctx);
910e4b17023SJohn Marino x = build_simple_mem_ref (x);
911e4b17023SJohn Marino }
912e4b17023SJohn Marino else if (is_taskreg_ctx (ctx))
913e4b17023SJohn Marino {
914e4b17023SJohn Marino bool by_ref = use_pointer_for_field (var, NULL);
915e4b17023SJohn Marino x = build_receiver_ref (var, by_ref, ctx);
916e4b17023SJohn Marino }
917e4b17023SJohn Marino else if (ctx->outer)
918e4b17023SJohn Marino x = lookup_decl (var, ctx->outer);
919e4b17023SJohn Marino else if (is_reference (var))
920e4b17023SJohn Marino /* This can happen with orphaned constructs. If var is reference, it is
921e4b17023SJohn Marino possible it is shared and as such valid. */
922e4b17023SJohn Marino x = var;
923e4b17023SJohn Marino else
924e4b17023SJohn Marino gcc_unreachable ();
925e4b17023SJohn Marino
926e4b17023SJohn Marino if (is_reference (var))
927e4b17023SJohn Marino x = build_simple_mem_ref (x);
928e4b17023SJohn Marino
929e4b17023SJohn Marino return x;
930e4b17023SJohn Marino }
931e4b17023SJohn Marino
932e4b17023SJohn Marino /* Build tree nodes to access the field for VAR on the sender side. */
933e4b17023SJohn Marino
934e4b17023SJohn Marino static tree
build_sender_ref(tree var,omp_context * ctx)935e4b17023SJohn Marino build_sender_ref (tree var, omp_context *ctx)
936e4b17023SJohn Marino {
937e4b17023SJohn Marino tree field = lookup_sfield (var, ctx);
938e4b17023SJohn Marino return omp_build_component_ref (ctx->sender_decl, field);
939e4b17023SJohn Marino }
940e4b17023SJohn Marino
941e4b17023SJohn Marino /* Add a new field for VAR inside the structure CTX->SENDER_DECL. */
942e4b17023SJohn Marino
943e4b17023SJohn Marino static void
install_var_field(tree var,bool by_ref,int mask,omp_context * ctx)944e4b17023SJohn Marino install_var_field (tree var, bool by_ref, int mask, omp_context *ctx)
945e4b17023SJohn Marino {
946e4b17023SJohn Marino tree field, type, sfield = NULL_TREE;
947e4b17023SJohn Marino
948e4b17023SJohn Marino gcc_assert ((mask & 1) == 0
949e4b17023SJohn Marino || !splay_tree_lookup (ctx->field_map, (splay_tree_key) var));
950e4b17023SJohn Marino gcc_assert ((mask & 2) == 0 || !ctx->sfield_map
951e4b17023SJohn Marino || !splay_tree_lookup (ctx->sfield_map, (splay_tree_key) var));
952e4b17023SJohn Marino
953e4b17023SJohn Marino type = TREE_TYPE (var);
954e4b17023SJohn Marino if (by_ref)
955e4b17023SJohn Marino type = build_pointer_type (type);
956e4b17023SJohn Marino else if ((mask & 3) == 1 && is_reference (var))
957e4b17023SJohn Marino type = TREE_TYPE (type);
958e4b17023SJohn Marino
959e4b17023SJohn Marino field = build_decl (DECL_SOURCE_LOCATION (var),
960e4b17023SJohn Marino FIELD_DECL, DECL_NAME (var), type);
961e4b17023SJohn Marino
962e4b17023SJohn Marino /* Remember what variable this field was created for. This does have a
963e4b17023SJohn Marino side effect of making dwarf2out ignore this member, so for helpful
964e4b17023SJohn Marino debugging we clear it later in delete_omp_context. */
965e4b17023SJohn Marino DECL_ABSTRACT_ORIGIN (field) = var;
966e4b17023SJohn Marino if (type == TREE_TYPE (var))
967e4b17023SJohn Marino {
968e4b17023SJohn Marino DECL_ALIGN (field) = DECL_ALIGN (var);
969e4b17023SJohn Marino DECL_USER_ALIGN (field) = DECL_USER_ALIGN (var);
970e4b17023SJohn Marino TREE_THIS_VOLATILE (field) = TREE_THIS_VOLATILE (var);
971e4b17023SJohn Marino }
972e4b17023SJohn Marino else
973e4b17023SJohn Marino DECL_ALIGN (field) = TYPE_ALIGN (type);
974e4b17023SJohn Marino
975e4b17023SJohn Marino if ((mask & 3) == 3)
976e4b17023SJohn Marino {
977e4b17023SJohn Marino insert_field_into_struct (ctx->record_type, field);
978e4b17023SJohn Marino if (ctx->srecord_type)
979e4b17023SJohn Marino {
980e4b17023SJohn Marino sfield = build_decl (DECL_SOURCE_LOCATION (var),
981e4b17023SJohn Marino FIELD_DECL, DECL_NAME (var), type);
982e4b17023SJohn Marino DECL_ABSTRACT_ORIGIN (sfield) = var;
983e4b17023SJohn Marino DECL_ALIGN (sfield) = DECL_ALIGN (field);
984e4b17023SJohn Marino DECL_USER_ALIGN (sfield) = DECL_USER_ALIGN (field);
985e4b17023SJohn Marino TREE_THIS_VOLATILE (sfield) = TREE_THIS_VOLATILE (field);
986e4b17023SJohn Marino insert_field_into_struct (ctx->srecord_type, sfield);
987e4b17023SJohn Marino }
988e4b17023SJohn Marino }
989e4b17023SJohn Marino else
990e4b17023SJohn Marino {
991e4b17023SJohn Marino if (ctx->srecord_type == NULL_TREE)
992e4b17023SJohn Marino {
993e4b17023SJohn Marino tree t;
994e4b17023SJohn Marino
995e4b17023SJohn Marino ctx->srecord_type = lang_hooks.types.make_type (RECORD_TYPE);
996e4b17023SJohn Marino ctx->sfield_map = splay_tree_new (splay_tree_compare_pointers, 0, 0);
997e4b17023SJohn Marino for (t = TYPE_FIELDS (ctx->record_type); t ; t = TREE_CHAIN (t))
998e4b17023SJohn Marino {
999e4b17023SJohn Marino sfield = build_decl (DECL_SOURCE_LOCATION (var),
1000e4b17023SJohn Marino FIELD_DECL, DECL_NAME (t), TREE_TYPE (t));
1001e4b17023SJohn Marino DECL_ABSTRACT_ORIGIN (sfield) = DECL_ABSTRACT_ORIGIN (t);
1002e4b17023SJohn Marino insert_field_into_struct (ctx->srecord_type, sfield);
1003e4b17023SJohn Marino splay_tree_insert (ctx->sfield_map,
1004e4b17023SJohn Marino (splay_tree_key) DECL_ABSTRACT_ORIGIN (t),
1005e4b17023SJohn Marino (splay_tree_value) sfield);
1006e4b17023SJohn Marino }
1007e4b17023SJohn Marino }
1008e4b17023SJohn Marino sfield = field;
1009e4b17023SJohn Marino insert_field_into_struct ((mask & 1) ? ctx->record_type
1010e4b17023SJohn Marino : ctx->srecord_type, field);
1011e4b17023SJohn Marino }
1012e4b17023SJohn Marino
1013e4b17023SJohn Marino if (mask & 1)
1014e4b17023SJohn Marino splay_tree_insert (ctx->field_map, (splay_tree_key) var,
1015e4b17023SJohn Marino (splay_tree_value) field);
1016e4b17023SJohn Marino if ((mask & 2) && ctx->sfield_map)
1017e4b17023SJohn Marino splay_tree_insert (ctx->sfield_map, (splay_tree_key) var,
1018e4b17023SJohn Marino (splay_tree_value) sfield);
1019e4b17023SJohn Marino }
1020e4b17023SJohn Marino
1021e4b17023SJohn Marino static tree
install_var_local(tree var,omp_context * ctx)1022e4b17023SJohn Marino install_var_local (tree var, omp_context *ctx)
1023e4b17023SJohn Marino {
1024e4b17023SJohn Marino tree new_var = omp_copy_decl_1 (var, ctx);
1025e4b17023SJohn Marino insert_decl_map (&ctx->cb, var, new_var);
1026e4b17023SJohn Marino return new_var;
1027e4b17023SJohn Marino }
1028e4b17023SJohn Marino
1029e4b17023SJohn Marino /* Adjust the replacement for DECL in CTX for the new context. This means
1030e4b17023SJohn Marino copying the DECL_VALUE_EXPR, and fixing up the type. */
1031e4b17023SJohn Marino
1032e4b17023SJohn Marino static void
fixup_remapped_decl(tree decl,omp_context * ctx,bool private_debug)1033e4b17023SJohn Marino fixup_remapped_decl (tree decl, omp_context *ctx, bool private_debug)
1034e4b17023SJohn Marino {
1035e4b17023SJohn Marino tree new_decl, size;
1036e4b17023SJohn Marino
1037e4b17023SJohn Marino new_decl = lookup_decl (decl, ctx);
1038e4b17023SJohn Marino
1039e4b17023SJohn Marino TREE_TYPE (new_decl) = remap_type (TREE_TYPE (decl), &ctx->cb);
1040e4b17023SJohn Marino
1041e4b17023SJohn Marino if ((!TREE_CONSTANT (DECL_SIZE (new_decl)) || private_debug)
1042e4b17023SJohn Marino && DECL_HAS_VALUE_EXPR_P (decl))
1043e4b17023SJohn Marino {
1044e4b17023SJohn Marino tree ve = DECL_VALUE_EXPR (decl);
1045e4b17023SJohn Marino walk_tree (&ve, copy_tree_body_r, &ctx->cb, NULL);
1046e4b17023SJohn Marino SET_DECL_VALUE_EXPR (new_decl, ve);
1047e4b17023SJohn Marino DECL_HAS_VALUE_EXPR_P (new_decl) = 1;
1048e4b17023SJohn Marino }
1049e4b17023SJohn Marino
1050e4b17023SJohn Marino if (!TREE_CONSTANT (DECL_SIZE (new_decl)))
1051e4b17023SJohn Marino {
1052e4b17023SJohn Marino size = remap_decl (DECL_SIZE (decl), &ctx->cb);
1053e4b17023SJohn Marino if (size == error_mark_node)
1054e4b17023SJohn Marino size = TYPE_SIZE (TREE_TYPE (new_decl));
1055e4b17023SJohn Marino DECL_SIZE (new_decl) = size;
1056e4b17023SJohn Marino
1057e4b17023SJohn Marino size = remap_decl (DECL_SIZE_UNIT (decl), &ctx->cb);
1058e4b17023SJohn Marino if (size == error_mark_node)
1059e4b17023SJohn Marino size = TYPE_SIZE_UNIT (TREE_TYPE (new_decl));
1060e4b17023SJohn Marino DECL_SIZE_UNIT (new_decl) = size;
1061e4b17023SJohn Marino }
1062e4b17023SJohn Marino }
1063e4b17023SJohn Marino
1064e4b17023SJohn Marino /* The callback for remap_decl. Search all containing contexts for a
1065e4b17023SJohn Marino mapping of the variable; this avoids having to duplicate the splay
1066e4b17023SJohn Marino tree ahead of time. We know a mapping doesn't already exist in the
1067e4b17023SJohn Marino given context. Create new mappings to implement default semantics. */
1068e4b17023SJohn Marino
1069e4b17023SJohn Marino static tree
omp_copy_decl(tree var,copy_body_data * cb)1070e4b17023SJohn Marino omp_copy_decl (tree var, copy_body_data *cb)
1071e4b17023SJohn Marino {
1072e4b17023SJohn Marino omp_context *ctx = (omp_context *) cb;
1073e4b17023SJohn Marino tree new_var;
1074e4b17023SJohn Marino
1075e4b17023SJohn Marino if (TREE_CODE (var) == LABEL_DECL)
1076e4b17023SJohn Marino {
1077e4b17023SJohn Marino new_var = create_artificial_label (DECL_SOURCE_LOCATION (var));
1078e4b17023SJohn Marino DECL_CONTEXT (new_var) = current_function_decl;
1079e4b17023SJohn Marino insert_decl_map (&ctx->cb, var, new_var);
1080e4b17023SJohn Marino return new_var;
1081e4b17023SJohn Marino }
1082e4b17023SJohn Marino
1083e4b17023SJohn Marino while (!is_taskreg_ctx (ctx))
1084e4b17023SJohn Marino {
1085e4b17023SJohn Marino ctx = ctx->outer;
1086e4b17023SJohn Marino if (ctx == NULL)
1087e4b17023SJohn Marino return var;
1088e4b17023SJohn Marino new_var = maybe_lookup_decl (var, ctx);
1089e4b17023SJohn Marino if (new_var)
1090e4b17023SJohn Marino return new_var;
1091e4b17023SJohn Marino }
1092e4b17023SJohn Marino
1093e4b17023SJohn Marino if (is_global_var (var) || decl_function_context (var) != ctx->cb.src_fn)
1094e4b17023SJohn Marino return var;
1095e4b17023SJohn Marino
1096e4b17023SJohn Marino return error_mark_node;
1097e4b17023SJohn Marino }
1098e4b17023SJohn Marino
1099e4b17023SJohn Marino
1100e4b17023SJohn Marino /* Return the parallel region associated with STMT. */
1101e4b17023SJohn Marino
1102e4b17023SJohn Marino /* Debugging dumps for parallel regions. */
1103e4b17023SJohn Marino void dump_omp_region (FILE *, struct omp_region *, int);
1104e4b17023SJohn Marino void debug_omp_region (struct omp_region *);
1105e4b17023SJohn Marino void debug_all_omp_regions (void);
1106e4b17023SJohn Marino
1107e4b17023SJohn Marino /* Dump the parallel region tree rooted at REGION. */
1108e4b17023SJohn Marino
1109e4b17023SJohn Marino void
dump_omp_region(FILE * file,struct omp_region * region,int indent)1110e4b17023SJohn Marino dump_omp_region (FILE *file, struct omp_region *region, int indent)
1111e4b17023SJohn Marino {
1112e4b17023SJohn Marino fprintf (file, "%*sbb %d: %s\n", indent, "", region->entry->index,
1113e4b17023SJohn Marino gimple_code_name[region->type]);
1114e4b17023SJohn Marino
1115e4b17023SJohn Marino if (region->inner)
1116e4b17023SJohn Marino dump_omp_region (file, region->inner, indent + 4);
1117e4b17023SJohn Marino
1118e4b17023SJohn Marino if (region->cont)
1119e4b17023SJohn Marino {
1120e4b17023SJohn Marino fprintf (file, "%*sbb %d: GIMPLE_OMP_CONTINUE\n", indent, "",
1121e4b17023SJohn Marino region->cont->index);
1122e4b17023SJohn Marino }
1123e4b17023SJohn Marino
1124e4b17023SJohn Marino if (region->exit)
1125e4b17023SJohn Marino fprintf (file, "%*sbb %d: GIMPLE_OMP_RETURN\n", indent, "",
1126e4b17023SJohn Marino region->exit->index);
1127e4b17023SJohn Marino else
1128e4b17023SJohn Marino fprintf (file, "%*s[no exit marker]\n", indent, "");
1129e4b17023SJohn Marino
1130e4b17023SJohn Marino if (region->next)
1131e4b17023SJohn Marino dump_omp_region (file, region->next, indent);
1132e4b17023SJohn Marino }
1133e4b17023SJohn Marino
1134e4b17023SJohn Marino DEBUG_FUNCTION void
debug_omp_region(struct omp_region * region)1135e4b17023SJohn Marino debug_omp_region (struct omp_region *region)
1136e4b17023SJohn Marino {
1137e4b17023SJohn Marino dump_omp_region (stderr, region, 0);
1138e4b17023SJohn Marino }
1139e4b17023SJohn Marino
1140e4b17023SJohn Marino DEBUG_FUNCTION void
debug_all_omp_regions(void)1141e4b17023SJohn Marino debug_all_omp_regions (void)
1142e4b17023SJohn Marino {
1143e4b17023SJohn Marino dump_omp_region (stderr, root_omp_region, 0);
1144e4b17023SJohn Marino }
1145e4b17023SJohn Marino
1146e4b17023SJohn Marino
1147e4b17023SJohn Marino /* Create a new parallel region starting at STMT inside region PARENT. */
1148e4b17023SJohn Marino
1149e4b17023SJohn Marino struct omp_region *
new_omp_region(basic_block bb,enum gimple_code type,struct omp_region * parent)1150e4b17023SJohn Marino new_omp_region (basic_block bb, enum gimple_code type,
1151e4b17023SJohn Marino struct omp_region *parent)
1152e4b17023SJohn Marino {
1153e4b17023SJohn Marino struct omp_region *region = XCNEW (struct omp_region);
1154e4b17023SJohn Marino
1155e4b17023SJohn Marino region->outer = parent;
1156e4b17023SJohn Marino region->entry = bb;
1157e4b17023SJohn Marino region->type = type;
1158e4b17023SJohn Marino
1159e4b17023SJohn Marino if (parent)
1160e4b17023SJohn Marino {
1161e4b17023SJohn Marino /* This is a nested region. Add it to the list of inner
1162e4b17023SJohn Marino regions in PARENT. */
1163e4b17023SJohn Marino region->next = parent->inner;
1164e4b17023SJohn Marino parent->inner = region;
1165e4b17023SJohn Marino }
1166e4b17023SJohn Marino else
1167e4b17023SJohn Marino {
1168e4b17023SJohn Marino /* This is a toplevel region. Add it to the list of toplevel
1169e4b17023SJohn Marino regions in ROOT_OMP_REGION. */
1170e4b17023SJohn Marino region->next = root_omp_region;
1171e4b17023SJohn Marino root_omp_region = region;
1172e4b17023SJohn Marino }
1173e4b17023SJohn Marino
1174e4b17023SJohn Marino return region;
1175e4b17023SJohn Marino }
1176e4b17023SJohn Marino
1177e4b17023SJohn Marino /* Release the memory associated with the region tree rooted at REGION. */
1178e4b17023SJohn Marino
1179e4b17023SJohn Marino static void
free_omp_region_1(struct omp_region * region)1180e4b17023SJohn Marino free_omp_region_1 (struct omp_region *region)
1181e4b17023SJohn Marino {
1182e4b17023SJohn Marino struct omp_region *i, *n;
1183e4b17023SJohn Marino
1184e4b17023SJohn Marino for (i = region->inner; i ; i = n)
1185e4b17023SJohn Marino {
1186e4b17023SJohn Marino n = i->next;
1187e4b17023SJohn Marino free_omp_region_1 (i);
1188e4b17023SJohn Marino }
1189e4b17023SJohn Marino
1190e4b17023SJohn Marino free (region);
1191e4b17023SJohn Marino }
1192e4b17023SJohn Marino
1193e4b17023SJohn Marino /* Release the memory for the entire omp region tree. */
1194e4b17023SJohn Marino
1195e4b17023SJohn Marino void
free_omp_regions(void)1196e4b17023SJohn Marino free_omp_regions (void)
1197e4b17023SJohn Marino {
1198e4b17023SJohn Marino struct omp_region *r, *n;
1199e4b17023SJohn Marino for (r = root_omp_region; r ; r = n)
1200e4b17023SJohn Marino {
1201e4b17023SJohn Marino n = r->next;
1202e4b17023SJohn Marino free_omp_region_1 (r);
1203e4b17023SJohn Marino }
1204e4b17023SJohn Marino root_omp_region = NULL;
1205e4b17023SJohn Marino }
1206e4b17023SJohn Marino
1207e4b17023SJohn Marino
1208e4b17023SJohn Marino /* Create a new context, with OUTER_CTX being the surrounding context. */
1209e4b17023SJohn Marino
1210e4b17023SJohn Marino static omp_context *
new_omp_context(gimple stmt,omp_context * outer_ctx)1211e4b17023SJohn Marino new_omp_context (gimple stmt, omp_context *outer_ctx)
1212e4b17023SJohn Marino {
1213e4b17023SJohn Marino omp_context *ctx = XCNEW (omp_context);
1214e4b17023SJohn Marino
1215e4b17023SJohn Marino splay_tree_insert (all_contexts, (splay_tree_key) stmt,
1216e4b17023SJohn Marino (splay_tree_value) ctx);
1217e4b17023SJohn Marino ctx->stmt = stmt;
1218e4b17023SJohn Marino
1219e4b17023SJohn Marino if (outer_ctx)
1220e4b17023SJohn Marino {
1221e4b17023SJohn Marino ctx->outer = outer_ctx;
1222e4b17023SJohn Marino ctx->cb = outer_ctx->cb;
1223e4b17023SJohn Marino ctx->cb.block = NULL;
1224e4b17023SJohn Marino ctx->depth = outer_ctx->depth + 1;
1225e4b17023SJohn Marino }
1226e4b17023SJohn Marino else
1227e4b17023SJohn Marino {
1228e4b17023SJohn Marino ctx->cb.src_fn = current_function_decl;
1229e4b17023SJohn Marino ctx->cb.dst_fn = current_function_decl;
1230e4b17023SJohn Marino ctx->cb.src_node = cgraph_get_node (current_function_decl);
1231e4b17023SJohn Marino gcc_checking_assert (ctx->cb.src_node);
1232e4b17023SJohn Marino ctx->cb.dst_node = ctx->cb.src_node;
1233e4b17023SJohn Marino ctx->cb.src_cfun = cfun;
1234e4b17023SJohn Marino ctx->cb.copy_decl = omp_copy_decl;
1235e4b17023SJohn Marino ctx->cb.eh_lp_nr = 0;
1236e4b17023SJohn Marino ctx->cb.transform_call_graph_edges = CB_CGE_MOVE;
1237e4b17023SJohn Marino ctx->depth = 1;
1238e4b17023SJohn Marino }
1239e4b17023SJohn Marino
1240e4b17023SJohn Marino ctx->cb.decl_map = pointer_map_create ();
1241e4b17023SJohn Marino
1242e4b17023SJohn Marino return ctx;
1243e4b17023SJohn Marino }
1244e4b17023SJohn Marino
1245e4b17023SJohn Marino static gimple_seq maybe_catch_exception (gimple_seq);
1246e4b17023SJohn Marino
1247e4b17023SJohn Marino /* Finalize task copyfn. */
1248e4b17023SJohn Marino
1249e4b17023SJohn Marino static void
finalize_task_copyfn(gimple task_stmt)1250e4b17023SJohn Marino finalize_task_copyfn (gimple task_stmt)
1251e4b17023SJohn Marino {
1252e4b17023SJohn Marino struct function *child_cfun;
1253e4b17023SJohn Marino tree child_fn, old_fn;
1254e4b17023SJohn Marino gimple_seq seq, new_seq;
1255e4b17023SJohn Marino gimple bind;
1256e4b17023SJohn Marino
1257e4b17023SJohn Marino child_fn = gimple_omp_task_copy_fn (task_stmt);
1258e4b17023SJohn Marino if (child_fn == NULL_TREE)
1259e4b17023SJohn Marino return;
1260e4b17023SJohn Marino
1261e4b17023SJohn Marino child_cfun = DECL_STRUCT_FUNCTION (child_fn);
1262e4b17023SJohn Marino
1263e4b17023SJohn Marino /* Inform the callgraph about the new function. */
1264e4b17023SJohn Marino DECL_STRUCT_FUNCTION (child_fn)->curr_properties
1265e4b17023SJohn Marino = cfun->curr_properties;
1266e4b17023SJohn Marino
1267e4b17023SJohn Marino old_fn = current_function_decl;
1268e4b17023SJohn Marino push_cfun (child_cfun);
1269e4b17023SJohn Marino current_function_decl = child_fn;
1270e4b17023SJohn Marino bind = gimplify_body (child_fn, false);
1271e4b17023SJohn Marino seq = gimple_seq_alloc ();
1272e4b17023SJohn Marino gimple_seq_add_stmt (&seq, bind);
1273e4b17023SJohn Marino new_seq = maybe_catch_exception (seq);
1274e4b17023SJohn Marino if (new_seq != seq)
1275e4b17023SJohn Marino {
1276e4b17023SJohn Marino bind = gimple_build_bind (NULL, new_seq, NULL);
1277e4b17023SJohn Marino seq = gimple_seq_alloc ();
1278e4b17023SJohn Marino gimple_seq_add_stmt (&seq, bind);
1279e4b17023SJohn Marino }
1280e4b17023SJohn Marino gimple_set_body (child_fn, seq);
1281e4b17023SJohn Marino pop_cfun ();
1282e4b17023SJohn Marino current_function_decl = old_fn;
1283e4b17023SJohn Marino
1284e4b17023SJohn Marino cgraph_add_new_function (child_fn, false);
1285e4b17023SJohn Marino }
1286e4b17023SJohn Marino
1287e4b17023SJohn Marino /* Destroy a omp_context data structures. Called through the splay tree
1288e4b17023SJohn Marino value delete callback. */
1289e4b17023SJohn Marino
1290e4b17023SJohn Marino static void
delete_omp_context(splay_tree_value value)1291e4b17023SJohn Marino delete_omp_context (splay_tree_value value)
1292e4b17023SJohn Marino {
1293e4b17023SJohn Marino omp_context *ctx = (omp_context *) value;
1294e4b17023SJohn Marino
1295e4b17023SJohn Marino pointer_map_destroy (ctx->cb.decl_map);
1296e4b17023SJohn Marino
1297e4b17023SJohn Marino if (ctx->field_map)
1298e4b17023SJohn Marino splay_tree_delete (ctx->field_map);
1299e4b17023SJohn Marino if (ctx->sfield_map)
1300e4b17023SJohn Marino splay_tree_delete (ctx->sfield_map);
1301e4b17023SJohn Marino
1302e4b17023SJohn Marino /* We hijacked DECL_ABSTRACT_ORIGIN earlier. We need to clear it before
1303e4b17023SJohn Marino it produces corrupt debug information. */
1304e4b17023SJohn Marino if (ctx->record_type)
1305e4b17023SJohn Marino {
1306e4b17023SJohn Marino tree t;
1307e4b17023SJohn Marino for (t = TYPE_FIELDS (ctx->record_type); t ; t = DECL_CHAIN (t))
1308e4b17023SJohn Marino DECL_ABSTRACT_ORIGIN (t) = NULL;
1309e4b17023SJohn Marino }
1310e4b17023SJohn Marino if (ctx->srecord_type)
1311e4b17023SJohn Marino {
1312e4b17023SJohn Marino tree t;
1313e4b17023SJohn Marino for (t = TYPE_FIELDS (ctx->srecord_type); t ; t = DECL_CHAIN (t))
1314e4b17023SJohn Marino DECL_ABSTRACT_ORIGIN (t) = NULL;
1315e4b17023SJohn Marino }
1316e4b17023SJohn Marino
1317e4b17023SJohn Marino if (is_task_ctx (ctx))
1318e4b17023SJohn Marino finalize_task_copyfn (ctx->stmt);
1319e4b17023SJohn Marino
1320e4b17023SJohn Marino XDELETE (ctx);
1321e4b17023SJohn Marino }
1322e4b17023SJohn Marino
1323e4b17023SJohn Marino /* Fix up RECEIVER_DECL with a type that has been remapped to the child
1324e4b17023SJohn Marino context. */
1325e4b17023SJohn Marino
1326e4b17023SJohn Marino static void
fixup_child_record_type(omp_context * ctx)1327e4b17023SJohn Marino fixup_child_record_type (omp_context *ctx)
1328e4b17023SJohn Marino {
1329e4b17023SJohn Marino tree f, type = ctx->record_type;
1330e4b17023SJohn Marino
1331e4b17023SJohn Marino /* ??? It isn't sufficient to just call remap_type here, because
1332e4b17023SJohn Marino variably_modified_type_p doesn't work the way we expect for
1333e4b17023SJohn Marino record types. Testing each field for whether it needs remapping
1334e4b17023SJohn Marino and creating a new record by hand works, however. */
1335e4b17023SJohn Marino for (f = TYPE_FIELDS (type); f ; f = DECL_CHAIN (f))
1336e4b17023SJohn Marino if (variably_modified_type_p (TREE_TYPE (f), ctx->cb.src_fn))
1337e4b17023SJohn Marino break;
1338e4b17023SJohn Marino if (f)
1339e4b17023SJohn Marino {
1340e4b17023SJohn Marino tree name, new_fields = NULL;
1341e4b17023SJohn Marino
1342e4b17023SJohn Marino type = lang_hooks.types.make_type (RECORD_TYPE);
1343e4b17023SJohn Marino name = DECL_NAME (TYPE_NAME (ctx->record_type));
1344e4b17023SJohn Marino name = build_decl (DECL_SOURCE_LOCATION (ctx->receiver_decl),
1345e4b17023SJohn Marino TYPE_DECL, name, type);
1346e4b17023SJohn Marino TYPE_NAME (type) = name;
1347e4b17023SJohn Marino
1348e4b17023SJohn Marino for (f = TYPE_FIELDS (ctx->record_type); f ; f = DECL_CHAIN (f))
1349e4b17023SJohn Marino {
1350e4b17023SJohn Marino tree new_f = copy_node (f);
1351e4b17023SJohn Marino DECL_CONTEXT (new_f) = type;
1352e4b17023SJohn Marino TREE_TYPE (new_f) = remap_type (TREE_TYPE (f), &ctx->cb);
1353e4b17023SJohn Marino DECL_CHAIN (new_f) = new_fields;
1354e4b17023SJohn Marino walk_tree (&DECL_SIZE (new_f), copy_tree_body_r, &ctx->cb, NULL);
1355e4b17023SJohn Marino walk_tree (&DECL_SIZE_UNIT (new_f), copy_tree_body_r,
1356e4b17023SJohn Marino &ctx->cb, NULL);
1357e4b17023SJohn Marino walk_tree (&DECL_FIELD_OFFSET (new_f), copy_tree_body_r,
1358e4b17023SJohn Marino &ctx->cb, NULL);
1359e4b17023SJohn Marino new_fields = new_f;
1360e4b17023SJohn Marino
1361e4b17023SJohn Marino /* Arrange to be able to look up the receiver field
1362e4b17023SJohn Marino given the sender field. */
1363e4b17023SJohn Marino splay_tree_insert (ctx->field_map, (splay_tree_key) f,
1364e4b17023SJohn Marino (splay_tree_value) new_f);
1365e4b17023SJohn Marino }
1366e4b17023SJohn Marino TYPE_FIELDS (type) = nreverse (new_fields);
1367e4b17023SJohn Marino layout_type (type);
1368e4b17023SJohn Marino }
1369e4b17023SJohn Marino
1370e4b17023SJohn Marino TREE_TYPE (ctx->receiver_decl) = build_pointer_type (type);
1371e4b17023SJohn Marino }
1372e4b17023SJohn Marino
1373e4b17023SJohn Marino /* Instantiate decls as necessary in CTX to satisfy the data sharing
1374e4b17023SJohn Marino specified by CLAUSES. */
1375e4b17023SJohn Marino
1376e4b17023SJohn Marino static void
scan_sharing_clauses(tree clauses,omp_context * ctx)1377e4b17023SJohn Marino scan_sharing_clauses (tree clauses, omp_context *ctx)
1378e4b17023SJohn Marino {
1379e4b17023SJohn Marino tree c, decl;
1380e4b17023SJohn Marino bool scan_array_reductions = false;
1381e4b17023SJohn Marino
1382e4b17023SJohn Marino for (c = clauses; c; c = OMP_CLAUSE_CHAIN (c))
1383e4b17023SJohn Marino {
1384e4b17023SJohn Marino bool by_ref;
1385e4b17023SJohn Marino
1386e4b17023SJohn Marino switch (OMP_CLAUSE_CODE (c))
1387e4b17023SJohn Marino {
1388e4b17023SJohn Marino case OMP_CLAUSE_PRIVATE:
1389e4b17023SJohn Marino decl = OMP_CLAUSE_DECL (c);
1390e4b17023SJohn Marino if (OMP_CLAUSE_PRIVATE_OUTER_REF (c))
1391e4b17023SJohn Marino goto do_private;
1392e4b17023SJohn Marino else if (!is_variable_sized (decl))
1393e4b17023SJohn Marino install_var_local (decl, ctx);
1394e4b17023SJohn Marino break;
1395e4b17023SJohn Marino
1396e4b17023SJohn Marino case OMP_CLAUSE_SHARED:
1397e4b17023SJohn Marino gcc_assert (is_taskreg_ctx (ctx));
1398e4b17023SJohn Marino decl = OMP_CLAUSE_DECL (c);
1399e4b17023SJohn Marino gcc_assert (!COMPLETE_TYPE_P (TREE_TYPE (decl))
1400e4b17023SJohn Marino || !is_variable_sized (decl));
1401e4b17023SJohn Marino /* Global variables don't need to be copied,
1402e4b17023SJohn Marino the receiver side will use them directly. */
1403e4b17023SJohn Marino if (is_global_var (maybe_lookup_decl_in_outer_ctx (decl, ctx)))
1404e4b17023SJohn Marino break;
1405e4b17023SJohn Marino by_ref = use_pointer_for_field (decl, ctx);
1406e4b17023SJohn Marino if (! TREE_READONLY (decl)
1407e4b17023SJohn Marino || TREE_ADDRESSABLE (decl)
1408e4b17023SJohn Marino || by_ref
1409e4b17023SJohn Marino || is_reference (decl))
1410e4b17023SJohn Marino {
1411e4b17023SJohn Marino install_var_field (decl, by_ref, 3, ctx);
1412e4b17023SJohn Marino install_var_local (decl, ctx);
1413e4b17023SJohn Marino break;
1414e4b17023SJohn Marino }
1415e4b17023SJohn Marino /* We don't need to copy const scalar vars back. */
1416e4b17023SJohn Marino OMP_CLAUSE_SET_CODE (c, OMP_CLAUSE_FIRSTPRIVATE);
1417e4b17023SJohn Marino goto do_private;
1418e4b17023SJohn Marino
1419e4b17023SJohn Marino case OMP_CLAUSE_LASTPRIVATE:
1420e4b17023SJohn Marino /* Let the corresponding firstprivate clause create
1421e4b17023SJohn Marino the variable. */
1422e4b17023SJohn Marino if (OMP_CLAUSE_LASTPRIVATE_FIRSTPRIVATE (c))
1423e4b17023SJohn Marino break;
1424e4b17023SJohn Marino /* FALLTHRU */
1425e4b17023SJohn Marino
1426e4b17023SJohn Marino case OMP_CLAUSE_FIRSTPRIVATE:
1427e4b17023SJohn Marino case OMP_CLAUSE_REDUCTION:
1428e4b17023SJohn Marino decl = OMP_CLAUSE_DECL (c);
1429e4b17023SJohn Marino do_private:
1430e4b17023SJohn Marino if (is_variable_sized (decl))
1431e4b17023SJohn Marino {
1432e4b17023SJohn Marino if (is_task_ctx (ctx))
1433e4b17023SJohn Marino install_var_field (decl, false, 1, ctx);
1434e4b17023SJohn Marino break;
1435e4b17023SJohn Marino }
1436e4b17023SJohn Marino else if (is_taskreg_ctx (ctx))
1437e4b17023SJohn Marino {
1438e4b17023SJohn Marino bool global
1439e4b17023SJohn Marino = is_global_var (maybe_lookup_decl_in_outer_ctx (decl, ctx));
1440e4b17023SJohn Marino by_ref = use_pointer_for_field (decl, NULL);
1441e4b17023SJohn Marino
1442e4b17023SJohn Marino if (is_task_ctx (ctx)
1443e4b17023SJohn Marino && (global || by_ref || is_reference (decl)))
1444e4b17023SJohn Marino {
1445e4b17023SJohn Marino install_var_field (decl, false, 1, ctx);
1446e4b17023SJohn Marino if (!global)
1447e4b17023SJohn Marino install_var_field (decl, by_ref, 2, ctx);
1448e4b17023SJohn Marino }
1449e4b17023SJohn Marino else if (!global)
1450e4b17023SJohn Marino install_var_field (decl, by_ref, 3, ctx);
1451e4b17023SJohn Marino }
1452e4b17023SJohn Marino install_var_local (decl, ctx);
1453e4b17023SJohn Marino break;
1454e4b17023SJohn Marino
1455e4b17023SJohn Marino case OMP_CLAUSE_COPYPRIVATE:
1456e4b17023SJohn Marino case OMP_CLAUSE_COPYIN:
1457e4b17023SJohn Marino decl = OMP_CLAUSE_DECL (c);
1458e4b17023SJohn Marino by_ref = use_pointer_for_field (decl, NULL);
1459e4b17023SJohn Marino install_var_field (decl, by_ref, 3, ctx);
1460e4b17023SJohn Marino break;
1461e4b17023SJohn Marino
1462e4b17023SJohn Marino case OMP_CLAUSE_DEFAULT:
1463e4b17023SJohn Marino ctx->default_kind = OMP_CLAUSE_DEFAULT_KIND (c);
1464e4b17023SJohn Marino break;
1465e4b17023SJohn Marino
1466e4b17023SJohn Marino case OMP_CLAUSE_FINAL:
1467e4b17023SJohn Marino case OMP_CLAUSE_IF:
1468e4b17023SJohn Marino case OMP_CLAUSE_NUM_THREADS:
1469e4b17023SJohn Marino case OMP_CLAUSE_SCHEDULE:
1470e4b17023SJohn Marino if (ctx->outer)
1471e4b17023SJohn Marino scan_omp_op (&OMP_CLAUSE_OPERAND (c, 0), ctx->outer);
1472e4b17023SJohn Marino break;
1473e4b17023SJohn Marino
1474e4b17023SJohn Marino case OMP_CLAUSE_NOWAIT:
1475e4b17023SJohn Marino case OMP_CLAUSE_ORDERED:
1476e4b17023SJohn Marino case OMP_CLAUSE_COLLAPSE:
1477e4b17023SJohn Marino case OMP_CLAUSE_UNTIED:
1478e4b17023SJohn Marino case OMP_CLAUSE_MERGEABLE:
1479e4b17023SJohn Marino break;
1480e4b17023SJohn Marino
1481e4b17023SJohn Marino default:
1482e4b17023SJohn Marino gcc_unreachable ();
1483e4b17023SJohn Marino }
1484e4b17023SJohn Marino }
1485e4b17023SJohn Marino
1486e4b17023SJohn Marino for (c = clauses; c; c = OMP_CLAUSE_CHAIN (c))
1487e4b17023SJohn Marino {
1488e4b17023SJohn Marino switch (OMP_CLAUSE_CODE (c))
1489e4b17023SJohn Marino {
1490e4b17023SJohn Marino case OMP_CLAUSE_LASTPRIVATE:
1491e4b17023SJohn Marino /* Let the corresponding firstprivate clause create
1492e4b17023SJohn Marino the variable. */
1493e4b17023SJohn Marino if (OMP_CLAUSE_LASTPRIVATE_GIMPLE_SEQ (c))
1494e4b17023SJohn Marino scan_array_reductions = true;
1495e4b17023SJohn Marino if (OMP_CLAUSE_LASTPRIVATE_FIRSTPRIVATE (c))
1496e4b17023SJohn Marino break;
1497e4b17023SJohn Marino /* FALLTHRU */
1498e4b17023SJohn Marino
1499e4b17023SJohn Marino case OMP_CLAUSE_PRIVATE:
1500e4b17023SJohn Marino case OMP_CLAUSE_FIRSTPRIVATE:
1501e4b17023SJohn Marino case OMP_CLAUSE_REDUCTION:
1502e4b17023SJohn Marino decl = OMP_CLAUSE_DECL (c);
1503e4b17023SJohn Marino if (is_variable_sized (decl))
1504e4b17023SJohn Marino install_var_local (decl, ctx);
1505e4b17023SJohn Marino fixup_remapped_decl (decl, ctx,
1506e4b17023SJohn Marino OMP_CLAUSE_CODE (c) == OMP_CLAUSE_PRIVATE
1507e4b17023SJohn Marino && OMP_CLAUSE_PRIVATE_DEBUG (c));
1508e4b17023SJohn Marino if (OMP_CLAUSE_CODE (c) == OMP_CLAUSE_REDUCTION
1509e4b17023SJohn Marino && OMP_CLAUSE_REDUCTION_PLACEHOLDER (c))
1510e4b17023SJohn Marino scan_array_reductions = true;
1511e4b17023SJohn Marino break;
1512e4b17023SJohn Marino
1513e4b17023SJohn Marino case OMP_CLAUSE_SHARED:
1514e4b17023SJohn Marino decl = OMP_CLAUSE_DECL (c);
1515e4b17023SJohn Marino if (! is_global_var (maybe_lookup_decl_in_outer_ctx (decl, ctx)))
1516e4b17023SJohn Marino fixup_remapped_decl (decl, ctx, false);
1517e4b17023SJohn Marino break;
1518e4b17023SJohn Marino
1519e4b17023SJohn Marino case OMP_CLAUSE_COPYPRIVATE:
1520e4b17023SJohn Marino case OMP_CLAUSE_COPYIN:
1521e4b17023SJohn Marino case OMP_CLAUSE_DEFAULT:
1522e4b17023SJohn Marino case OMP_CLAUSE_IF:
1523e4b17023SJohn Marino case OMP_CLAUSE_NUM_THREADS:
1524e4b17023SJohn Marino case OMP_CLAUSE_SCHEDULE:
1525e4b17023SJohn Marino case OMP_CLAUSE_NOWAIT:
1526e4b17023SJohn Marino case OMP_CLAUSE_ORDERED:
1527e4b17023SJohn Marino case OMP_CLAUSE_COLLAPSE:
1528e4b17023SJohn Marino case OMP_CLAUSE_UNTIED:
1529e4b17023SJohn Marino case OMP_CLAUSE_FINAL:
1530e4b17023SJohn Marino case OMP_CLAUSE_MERGEABLE:
1531e4b17023SJohn Marino break;
1532e4b17023SJohn Marino
1533e4b17023SJohn Marino default:
1534e4b17023SJohn Marino gcc_unreachable ();
1535e4b17023SJohn Marino }
1536e4b17023SJohn Marino }
1537e4b17023SJohn Marino
1538e4b17023SJohn Marino if (scan_array_reductions)
1539e4b17023SJohn Marino for (c = clauses; c; c = OMP_CLAUSE_CHAIN (c))
1540e4b17023SJohn Marino if (OMP_CLAUSE_CODE (c) == OMP_CLAUSE_REDUCTION
1541e4b17023SJohn Marino && OMP_CLAUSE_REDUCTION_PLACEHOLDER (c))
1542e4b17023SJohn Marino {
1543e4b17023SJohn Marino scan_omp (OMP_CLAUSE_REDUCTION_GIMPLE_INIT (c), ctx);
1544e4b17023SJohn Marino scan_omp (OMP_CLAUSE_REDUCTION_GIMPLE_MERGE (c), ctx);
1545e4b17023SJohn Marino }
1546e4b17023SJohn Marino else if (OMP_CLAUSE_CODE (c) == OMP_CLAUSE_LASTPRIVATE
1547e4b17023SJohn Marino && OMP_CLAUSE_LASTPRIVATE_GIMPLE_SEQ (c))
1548e4b17023SJohn Marino scan_omp (OMP_CLAUSE_LASTPRIVATE_GIMPLE_SEQ (c), ctx);
1549e4b17023SJohn Marino }
1550e4b17023SJohn Marino
1551e4b17023SJohn Marino /* Create a new name for omp child function. Returns an identifier. */
1552e4b17023SJohn Marino
1553e4b17023SJohn Marino static GTY(()) unsigned int tmp_ompfn_id_num;
1554e4b17023SJohn Marino
1555e4b17023SJohn Marino static tree
create_omp_child_function_name(bool task_copy)1556e4b17023SJohn Marino create_omp_child_function_name (bool task_copy)
1557e4b17023SJohn Marino {
1558e4b17023SJohn Marino return (clone_function_name (current_function_decl,
1559e4b17023SJohn Marino task_copy ? "_omp_cpyfn" : "_omp_fn"));
1560e4b17023SJohn Marino }
1561e4b17023SJohn Marino
1562e4b17023SJohn Marino /* Build a decl for the omp child function. It'll not contain a body
1563e4b17023SJohn Marino yet, just the bare decl. */
1564e4b17023SJohn Marino
1565e4b17023SJohn Marino static void
create_omp_child_function(omp_context * ctx,bool task_copy)1566e4b17023SJohn Marino create_omp_child_function (omp_context *ctx, bool task_copy)
1567e4b17023SJohn Marino {
1568e4b17023SJohn Marino tree decl, type, name, t;
1569e4b17023SJohn Marino
1570e4b17023SJohn Marino name = create_omp_child_function_name (task_copy);
1571e4b17023SJohn Marino if (task_copy)
1572e4b17023SJohn Marino type = build_function_type_list (void_type_node, ptr_type_node,
1573e4b17023SJohn Marino ptr_type_node, NULL_TREE);
1574e4b17023SJohn Marino else
1575e4b17023SJohn Marino type = build_function_type_list (void_type_node, ptr_type_node, NULL_TREE);
1576e4b17023SJohn Marino
1577e4b17023SJohn Marino decl = build_decl (gimple_location (ctx->stmt),
1578e4b17023SJohn Marino FUNCTION_DECL, name, type);
1579e4b17023SJohn Marino
1580e4b17023SJohn Marino if (!task_copy)
1581e4b17023SJohn Marino ctx->cb.dst_fn = decl;
1582e4b17023SJohn Marino else
1583e4b17023SJohn Marino gimple_omp_task_set_copy_fn (ctx->stmt, decl);
1584e4b17023SJohn Marino
1585e4b17023SJohn Marino TREE_STATIC (decl) = 1;
1586e4b17023SJohn Marino TREE_USED (decl) = 1;
1587e4b17023SJohn Marino DECL_ARTIFICIAL (decl) = 1;
1588e4b17023SJohn Marino DECL_NAMELESS (decl) = 1;
1589e4b17023SJohn Marino DECL_IGNORED_P (decl) = 0;
1590e4b17023SJohn Marino TREE_PUBLIC (decl) = 0;
1591e4b17023SJohn Marino DECL_UNINLINABLE (decl) = 1;
1592e4b17023SJohn Marino DECL_EXTERNAL (decl) = 0;
1593e4b17023SJohn Marino DECL_CONTEXT (decl) = NULL_TREE;
1594e4b17023SJohn Marino DECL_INITIAL (decl) = make_node (BLOCK);
1595e4b17023SJohn Marino
1596e4b17023SJohn Marino t = build_decl (DECL_SOURCE_LOCATION (decl),
1597e4b17023SJohn Marino RESULT_DECL, NULL_TREE, void_type_node);
1598e4b17023SJohn Marino DECL_ARTIFICIAL (t) = 1;
1599e4b17023SJohn Marino DECL_IGNORED_P (t) = 1;
1600e4b17023SJohn Marino DECL_CONTEXT (t) = decl;
1601e4b17023SJohn Marino DECL_RESULT (decl) = t;
1602e4b17023SJohn Marino
1603e4b17023SJohn Marino t = build_decl (DECL_SOURCE_LOCATION (decl),
1604e4b17023SJohn Marino PARM_DECL, get_identifier (".omp_data_i"), ptr_type_node);
1605e4b17023SJohn Marino DECL_ARTIFICIAL (t) = 1;
1606e4b17023SJohn Marino DECL_NAMELESS (t) = 1;
1607e4b17023SJohn Marino DECL_ARG_TYPE (t) = ptr_type_node;
1608e4b17023SJohn Marino DECL_CONTEXT (t) = current_function_decl;
1609e4b17023SJohn Marino TREE_USED (t) = 1;
1610e4b17023SJohn Marino DECL_ARGUMENTS (decl) = t;
1611e4b17023SJohn Marino if (!task_copy)
1612e4b17023SJohn Marino ctx->receiver_decl = t;
1613e4b17023SJohn Marino else
1614e4b17023SJohn Marino {
1615e4b17023SJohn Marino t = build_decl (DECL_SOURCE_LOCATION (decl),
1616e4b17023SJohn Marino PARM_DECL, get_identifier (".omp_data_o"),
1617e4b17023SJohn Marino ptr_type_node);
1618e4b17023SJohn Marino DECL_ARTIFICIAL (t) = 1;
1619e4b17023SJohn Marino DECL_NAMELESS (t) = 1;
1620e4b17023SJohn Marino DECL_ARG_TYPE (t) = ptr_type_node;
1621e4b17023SJohn Marino DECL_CONTEXT (t) = current_function_decl;
1622e4b17023SJohn Marino TREE_USED (t) = 1;
1623e4b17023SJohn Marino TREE_ADDRESSABLE (t) = 1;
1624e4b17023SJohn Marino DECL_CHAIN (t) = DECL_ARGUMENTS (decl);
1625e4b17023SJohn Marino DECL_ARGUMENTS (decl) = t;
1626e4b17023SJohn Marino }
1627e4b17023SJohn Marino
1628e4b17023SJohn Marino /* Allocate memory for the function structure. The call to
1629e4b17023SJohn Marino allocate_struct_function clobbers CFUN, so we need to restore
1630e4b17023SJohn Marino it afterward. */
1631e4b17023SJohn Marino push_struct_function (decl);
1632e4b17023SJohn Marino cfun->function_end_locus = gimple_location (ctx->stmt);
1633e4b17023SJohn Marino pop_cfun ();
1634e4b17023SJohn Marino }
1635e4b17023SJohn Marino
1636e4b17023SJohn Marino
1637e4b17023SJohn Marino /* Scan an OpenMP parallel directive. */
1638e4b17023SJohn Marino
1639e4b17023SJohn Marino static void
scan_omp_parallel(gimple_stmt_iterator * gsi,omp_context * outer_ctx)1640e4b17023SJohn Marino scan_omp_parallel (gimple_stmt_iterator *gsi, omp_context *outer_ctx)
1641e4b17023SJohn Marino {
1642e4b17023SJohn Marino omp_context *ctx;
1643e4b17023SJohn Marino tree name;
1644e4b17023SJohn Marino gimple stmt = gsi_stmt (*gsi);
1645e4b17023SJohn Marino
1646e4b17023SJohn Marino /* Ignore parallel directives with empty bodies, unless there
1647e4b17023SJohn Marino are copyin clauses. */
1648e4b17023SJohn Marino if (optimize > 0
1649e4b17023SJohn Marino && empty_body_p (gimple_omp_body (stmt))
1650e4b17023SJohn Marino && find_omp_clause (gimple_omp_parallel_clauses (stmt),
1651e4b17023SJohn Marino OMP_CLAUSE_COPYIN) == NULL)
1652e4b17023SJohn Marino {
1653e4b17023SJohn Marino gsi_replace (gsi, gimple_build_nop (), false);
1654e4b17023SJohn Marino return;
1655e4b17023SJohn Marino }
1656e4b17023SJohn Marino
1657e4b17023SJohn Marino ctx = new_omp_context (stmt, outer_ctx);
1658e4b17023SJohn Marino if (taskreg_nesting_level > 1)
1659e4b17023SJohn Marino ctx->is_nested = true;
1660e4b17023SJohn Marino ctx->field_map = splay_tree_new (splay_tree_compare_pointers, 0, 0);
1661e4b17023SJohn Marino ctx->default_kind = OMP_CLAUSE_DEFAULT_SHARED;
1662e4b17023SJohn Marino ctx->record_type = lang_hooks.types.make_type (RECORD_TYPE);
1663e4b17023SJohn Marino name = create_tmp_var_name (".omp_data_s");
1664e4b17023SJohn Marino name = build_decl (gimple_location (stmt),
1665e4b17023SJohn Marino TYPE_DECL, name, ctx->record_type);
1666e4b17023SJohn Marino DECL_ARTIFICIAL (name) = 1;
1667e4b17023SJohn Marino DECL_NAMELESS (name) = 1;
1668e4b17023SJohn Marino TYPE_NAME (ctx->record_type) = name;
1669e4b17023SJohn Marino create_omp_child_function (ctx, false);
1670e4b17023SJohn Marino gimple_omp_parallel_set_child_fn (stmt, ctx->cb.dst_fn);
1671e4b17023SJohn Marino
1672e4b17023SJohn Marino scan_sharing_clauses (gimple_omp_parallel_clauses (stmt), ctx);
1673e4b17023SJohn Marino scan_omp (gimple_omp_body (stmt), ctx);
1674e4b17023SJohn Marino
1675e4b17023SJohn Marino if (TYPE_FIELDS (ctx->record_type) == NULL)
1676e4b17023SJohn Marino ctx->record_type = ctx->receiver_decl = NULL;
1677e4b17023SJohn Marino else
1678e4b17023SJohn Marino {
1679e4b17023SJohn Marino layout_type (ctx->record_type);
1680e4b17023SJohn Marino fixup_child_record_type (ctx);
1681e4b17023SJohn Marino }
1682e4b17023SJohn Marino }
1683e4b17023SJohn Marino
1684e4b17023SJohn Marino /* Scan an OpenMP task directive. */
1685e4b17023SJohn Marino
1686e4b17023SJohn Marino static void
scan_omp_task(gimple_stmt_iterator * gsi,omp_context * outer_ctx)1687e4b17023SJohn Marino scan_omp_task (gimple_stmt_iterator *gsi, omp_context *outer_ctx)
1688e4b17023SJohn Marino {
1689e4b17023SJohn Marino omp_context *ctx;
1690e4b17023SJohn Marino tree name, t;
1691e4b17023SJohn Marino gimple stmt = gsi_stmt (*gsi);
1692e4b17023SJohn Marino location_t loc = gimple_location (stmt);
1693e4b17023SJohn Marino
1694e4b17023SJohn Marino /* Ignore task directives with empty bodies. */
1695e4b17023SJohn Marino if (optimize > 0
1696e4b17023SJohn Marino && empty_body_p (gimple_omp_body (stmt)))
1697e4b17023SJohn Marino {
1698e4b17023SJohn Marino gsi_replace (gsi, gimple_build_nop (), false);
1699e4b17023SJohn Marino return;
1700e4b17023SJohn Marino }
1701e4b17023SJohn Marino
1702e4b17023SJohn Marino ctx = new_omp_context (stmt, outer_ctx);
1703e4b17023SJohn Marino if (taskreg_nesting_level > 1)
1704e4b17023SJohn Marino ctx->is_nested = true;
1705e4b17023SJohn Marino ctx->field_map = splay_tree_new (splay_tree_compare_pointers, 0, 0);
1706e4b17023SJohn Marino ctx->default_kind = OMP_CLAUSE_DEFAULT_SHARED;
1707e4b17023SJohn Marino ctx->record_type = lang_hooks.types.make_type (RECORD_TYPE);
1708e4b17023SJohn Marino name = create_tmp_var_name (".omp_data_s");
1709e4b17023SJohn Marino name = build_decl (gimple_location (stmt),
1710e4b17023SJohn Marino TYPE_DECL, name, ctx->record_type);
1711e4b17023SJohn Marino DECL_ARTIFICIAL (name) = 1;
1712e4b17023SJohn Marino DECL_NAMELESS (name) = 1;
1713e4b17023SJohn Marino TYPE_NAME (ctx->record_type) = name;
1714e4b17023SJohn Marino create_omp_child_function (ctx, false);
1715e4b17023SJohn Marino gimple_omp_task_set_child_fn (stmt, ctx->cb.dst_fn);
1716e4b17023SJohn Marino
1717e4b17023SJohn Marino scan_sharing_clauses (gimple_omp_task_clauses (stmt), ctx);
1718e4b17023SJohn Marino
1719e4b17023SJohn Marino if (ctx->srecord_type)
1720e4b17023SJohn Marino {
1721e4b17023SJohn Marino name = create_tmp_var_name (".omp_data_a");
1722e4b17023SJohn Marino name = build_decl (gimple_location (stmt),
1723e4b17023SJohn Marino TYPE_DECL, name, ctx->srecord_type);
1724e4b17023SJohn Marino DECL_ARTIFICIAL (name) = 1;
1725e4b17023SJohn Marino DECL_NAMELESS (name) = 1;
1726e4b17023SJohn Marino TYPE_NAME (ctx->srecord_type) = name;
1727e4b17023SJohn Marino create_omp_child_function (ctx, true);
1728e4b17023SJohn Marino }
1729e4b17023SJohn Marino
1730e4b17023SJohn Marino scan_omp (gimple_omp_body (stmt), ctx);
1731e4b17023SJohn Marino
1732e4b17023SJohn Marino if (TYPE_FIELDS (ctx->record_type) == NULL)
1733e4b17023SJohn Marino {
1734e4b17023SJohn Marino ctx->record_type = ctx->receiver_decl = NULL;
1735e4b17023SJohn Marino t = build_int_cst (long_integer_type_node, 0);
1736e4b17023SJohn Marino gimple_omp_task_set_arg_size (stmt, t);
1737e4b17023SJohn Marino t = build_int_cst (long_integer_type_node, 1);
1738e4b17023SJohn Marino gimple_omp_task_set_arg_align (stmt, t);
1739e4b17023SJohn Marino }
1740e4b17023SJohn Marino else
1741e4b17023SJohn Marino {
1742e4b17023SJohn Marino tree *p, vla_fields = NULL_TREE, *q = &vla_fields;
1743e4b17023SJohn Marino /* Move VLA fields to the end. */
1744e4b17023SJohn Marino p = &TYPE_FIELDS (ctx->record_type);
1745e4b17023SJohn Marino while (*p)
1746e4b17023SJohn Marino if (!TYPE_SIZE_UNIT (TREE_TYPE (*p))
1747e4b17023SJohn Marino || ! TREE_CONSTANT (TYPE_SIZE_UNIT (TREE_TYPE (*p))))
1748e4b17023SJohn Marino {
1749e4b17023SJohn Marino *q = *p;
1750e4b17023SJohn Marino *p = TREE_CHAIN (*p);
1751e4b17023SJohn Marino TREE_CHAIN (*q) = NULL_TREE;
1752e4b17023SJohn Marino q = &TREE_CHAIN (*q);
1753e4b17023SJohn Marino }
1754e4b17023SJohn Marino else
1755e4b17023SJohn Marino p = &DECL_CHAIN (*p);
1756e4b17023SJohn Marino *p = vla_fields;
1757e4b17023SJohn Marino layout_type (ctx->record_type);
1758e4b17023SJohn Marino fixup_child_record_type (ctx);
1759e4b17023SJohn Marino if (ctx->srecord_type)
1760e4b17023SJohn Marino layout_type (ctx->srecord_type);
1761e4b17023SJohn Marino t = fold_convert_loc (loc, long_integer_type_node,
1762e4b17023SJohn Marino TYPE_SIZE_UNIT (ctx->record_type));
1763e4b17023SJohn Marino gimple_omp_task_set_arg_size (stmt, t);
1764e4b17023SJohn Marino t = build_int_cst (long_integer_type_node,
1765e4b17023SJohn Marino TYPE_ALIGN_UNIT (ctx->record_type));
1766e4b17023SJohn Marino gimple_omp_task_set_arg_align (stmt, t);
1767e4b17023SJohn Marino }
1768e4b17023SJohn Marino }
1769e4b17023SJohn Marino
1770e4b17023SJohn Marino
1771e4b17023SJohn Marino /* Scan an OpenMP loop directive. */
1772e4b17023SJohn Marino
1773e4b17023SJohn Marino static void
scan_omp_for(gimple stmt,omp_context * outer_ctx)1774e4b17023SJohn Marino scan_omp_for (gimple stmt, omp_context *outer_ctx)
1775e4b17023SJohn Marino {
1776e4b17023SJohn Marino omp_context *ctx;
1777e4b17023SJohn Marino size_t i;
1778e4b17023SJohn Marino
1779e4b17023SJohn Marino ctx = new_omp_context (stmt, outer_ctx);
1780e4b17023SJohn Marino
1781e4b17023SJohn Marino scan_sharing_clauses (gimple_omp_for_clauses (stmt), ctx);
1782e4b17023SJohn Marino
1783e4b17023SJohn Marino scan_omp (gimple_omp_for_pre_body (stmt), ctx);
1784e4b17023SJohn Marino for (i = 0; i < gimple_omp_for_collapse (stmt); i++)
1785e4b17023SJohn Marino {
1786e4b17023SJohn Marino scan_omp_op (gimple_omp_for_index_ptr (stmt, i), ctx);
1787e4b17023SJohn Marino scan_omp_op (gimple_omp_for_initial_ptr (stmt, i), ctx);
1788e4b17023SJohn Marino scan_omp_op (gimple_omp_for_final_ptr (stmt, i), ctx);
1789e4b17023SJohn Marino scan_omp_op (gimple_omp_for_incr_ptr (stmt, i), ctx);
1790e4b17023SJohn Marino }
1791e4b17023SJohn Marino scan_omp (gimple_omp_body (stmt), ctx);
1792e4b17023SJohn Marino }
1793e4b17023SJohn Marino
1794e4b17023SJohn Marino /* Scan an OpenMP sections directive. */
1795e4b17023SJohn Marino
1796e4b17023SJohn Marino static void
scan_omp_sections(gimple stmt,omp_context * outer_ctx)1797e4b17023SJohn Marino scan_omp_sections (gimple stmt, omp_context *outer_ctx)
1798e4b17023SJohn Marino {
1799e4b17023SJohn Marino omp_context *ctx;
1800e4b17023SJohn Marino
1801e4b17023SJohn Marino ctx = new_omp_context (stmt, outer_ctx);
1802e4b17023SJohn Marino scan_sharing_clauses (gimple_omp_sections_clauses (stmt), ctx);
1803e4b17023SJohn Marino scan_omp (gimple_omp_body (stmt), ctx);
1804e4b17023SJohn Marino }
1805e4b17023SJohn Marino
1806e4b17023SJohn Marino /* Scan an OpenMP single directive. */
1807e4b17023SJohn Marino
1808e4b17023SJohn Marino static void
scan_omp_single(gimple stmt,omp_context * outer_ctx)1809e4b17023SJohn Marino scan_omp_single (gimple stmt, omp_context *outer_ctx)
1810e4b17023SJohn Marino {
1811e4b17023SJohn Marino omp_context *ctx;
1812e4b17023SJohn Marino tree name;
1813e4b17023SJohn Marino
1814e4b17023SJohn Marino ctx = new_omp_context (stmt, outer_ctx);
1815e4b17023SJohn Marino ctx->field_map = splay_tree_new (splay_tree_compare_pointers, 0, 0);
1816e4b17023SJohn Marino ctx->record_type = lang_hooks.types.make_type (RECORD_TYPE);
1817e4b17023SJohn Marino name = create_tmp_var_name (".omp_copy_s");
1818e4b17023SJohn Marino name = build_decl (gimple_location (stmt),
1819e4b17023SJohn Marino TYPE_DECL, name, ctx->record_type);
1820e4b17023SJohn Marino TYPE_NAME (ctx->record_type) = name;
1821e4b17023SJohn Marino
1822e4b17023SJohn Marino scan_sharing_clauses (gimple_omp_single_clauses (stmt), ctx);
1823e4b17023SJohn Marino scan_omp (gimple_omp_body (stmt), ctx);
1824e4b17023SJohn Marino
1825e4b17023SJohn Marino if (TYPE_FIELDS (ctx->record_type) == NULL)
1826e4b17023SJohn Marino ctx->record_type = NULL;
1827e4b17023SJohn Marino else
1828e4b17023SJohn Marino layout_type (ctx->record_type);
1829e4b17023SJohn Marino }
1830e4b17023SJohn Marino
1831e4b17023SJohn Marino
1832e4b17023SJohn Marino /* Check OpenMP nesting restrictions. */
1833e4b17023SJohn Marino static bool
check_omp_nesting_restrictions(gimple stmt,omp_context * ctx)1834e4b17023SJohn Marino check_omp_nesting_restrictions (gimple stmt, omp_context *ctx)
1835e4b17023SJohn Marino {
1836e4b17023SJohn Marino switch (gimple_code (stmt))
1837e4b17023SJohn Marino {
1838e4b17023SJohn Marino case GIMPLE_OMP_FOR:
1839e4b17023SJohn Marino case GIMPLE_OMP_SECTIONS:
1840e4b17023SJohn Marino case GIMPLE_OMP_SINGLE:
1841e4b17023SJohn Marino case GIMPLE_CALL:
1842e4b17023SJohn Marino for (; ctx != NULL; ctx = ctx->outer)
1843e4b17023SJohn Marino switch (gimple_code (ctx->stmt))
1844e4b17023SJohn Marino {
1845e4b17023SJohn Marino case GIMPLE_OMP_FOR:
1846e4b17023SJohn Marino case GIMPLE_OMP_SECTIONS:
1847e4b17023SJohn Marino case GIMPLE_OMP_SINGLE:
1848e4b17023SJohn Marino case GIMPLE_OMP_ORDERED:
1849e4b17023SJohn Marino case GIMPLE_OMP_MASTER:
1850e4b17023SJohn Marino case GIMPLE_OMP_TASK:
1851e4b17023SJohn Marino if (is_gimple_call (stmt))
1852e4b17023SJohn Marino {
1853e4b17023SJohn Marino error_at (gimple_location (stmt),
1854e4b17023SJohn Marino "barrier region may not be closely nested inside "
1855e4b17023SJohn Marino "of work-sharing, critical, ordered, master or "
1856e4b17023SJohn Marino "explicit task region");
1857e4b17023SJohn Marino return false;
1858e4b17023SJohn Marino }
1859e4b17023SJohn Marino error_at (gimple_location (stmt),
1860e4b17023SJohn Marino "work-sharing region may not be closely nested inside "
1861e4b17023SJohn Marino "of work-sharing, critical, ordered, master or explicit "
1862e4b17023SJohn Marino "task region");
1863e4b17023SJohn Marino return false;
1864e4b17023SJohn Marino case GIMPLE_OMP_PARALLEL:
1865e4b17023SJohn Marino return true;
1866e4b17023SJohn Marino default:
1867e4b17023SJohn Marino break;
1868e4b17023SJohn Marino }
1869e4b17023SJohn Marino break;
1870e4b17023SJohn Marino case GIMPLE_OMP_MASTER:
1871e4b17023SJohn Marino for (; ctx != NULL; ctx = ctx->outer)
1872e4b17023SJohn Marino switch (gimple_code (ctx->stmt))
1873e4b17023SJohn Marino {
1874e4b17023SJohn Marino case GIMPLE_OMP_FOR:
1875e4b17023SJohn Marino case GIMPLE_OMP_SECTIONS:
1876e4b17023SJohn Marino case GIMPLE_OMP_SINGLE:
1877e4b17023SJohn Marino case GIMPLE_OMP_TASK:
1878e4b17023SJohn Marino error_at (gimple_location (stmt),
1879e4b17023SJohn Marino "master region may not be closely nested inside "
1880e4b17023SJohn Marino "of work-sharing or explicit task region");
1881e4b17023SJohn Marino return false;
1882e4b17023SJohn Marino case GIMPLE_OMP_PARALLEL:
1883e4b17023SJohn Marino return true;
1884e4b17023SJohn Marino default:
1885e4b17023SJohn Marino break;
1886e4b17023SJohn Marino }
1887e4b17023SJohn Marino break;
1888e4b17023SJohn Marino case GIMPLE_OMP_ORDERED:
1889e4b17023SJohn Marino for (; ctx != NULL; ctx = ctx->outer)
1890e4b17023SJohn Marino switch (gimple_code (ctx->stmt))
1891e4b17023SJohn Marino {
1892e4b17023SJohn Marino case GIMPLE_OMP_CRITICAL:
1893e4b17023SJohn Marino case GIMPLE_OMP_TASK:
1894e4b17023SJohn Marino error_at (gimple_location (stmt),
1895e4b17023SJohn Marino "ordered region may not be closely nested inside "
1896e4b17023SJohn Marino "of critical or explicit task region");
1897e4b17023SJohn Marino return false;
1898e4b17023SJohn Marino case GIMPLE_OMP_FOR:
1899e4b17023SJohn Marino if (find_omp_clause (gimple_omp_for_clauses (ctx->stmt),
1900e4b17023SJohn Marino OMP_CLAUSE_ORDERED) == NULL)
1901e4b17023SJohn Marino {
1902e4b17023SJohn Marino error_at (gimple_location (stmt),
1903e4b17023SJohn Marino "ordered region must be closely nested inside "
1904e4b17023SJohn Marino "a loop region with an ordered clause");
1905e4b17023SJohn Marino return false;
1906e4b17023SJohn Marino }
1907e4b17023SJohn Marino return true;
1908e4b17023SJohn Marino case GIMPLE_OMP_PARALLEL:
1909e4b17023SJohn Marino return true;
1910e4b17023SJohn Marino default:
1911e4b17023SJohn Marino break;
1912e4b17023SJohn Marino }
1913e4b17023SJohn Marino break;
1914e4b17023SJohn Marino case GIMPLE_OMP_CRITICAL:
1915e4b17023SJohn Marino for (; ctx != NULL; ctx = ctx->outer)
1916e4b17023SJohn Marino if (gimple_code (ctx->stmt) == GIMPLE_OMP_CRITICAL
1917e4b17023SJohn Marino && (gimple_omp_critical_name (stmt)
1918e4b17023SJohn Marino == gimple_omp_critical_name (ctx->stmt)))
1919e4b17023SJohn Marino {
1920e4b17023SJohn Marino error_at (gimple_location (stmt),
1921e4b17023SJohn Marino "critical region may not be nested inside a critical "
1922e4b17023SJohn Marino "region with the same name");
1923e4b17023SJohn Marino return false;
1924e4b17023SJohn Marino }
1925e4b17023SJohn Marino break;
1926e4b17023SJohn Marino default:
1927e4b17023SJohn Marino break;
1928e4b17023SJohn Marino }
1929e4b17023SJohn Marino return true;
1930e4b17023SJohn Marino }
1931e4b17023SJohn Marino
1932e4b17023SJohn Marino
1933e4b17023SJohn Marino /* Helper function scan_omp.
1934e4b17023SJohn Marino
1935e4b17023SJohn Marino Callback for walk_tree or operators in walk_gimple_stmt used to
1936e4b17023SJohn Marino scan for OpenMP directives in TP. */
1937e4b17023SJohn Marino
1938e4b17023SJohn Marino static tree
scan_omp_1_op(tree * tp,int * walk_subtrees,void * data)1939e4b17023SJohn Marino scan_omp_1_op (tree *tp, int *walk_subtrees, void *data)
1940e4b17023SJohn Marino {
1941e4b17023SJohn Marino struct walk_stmt_info *wi = (struct walk_stmt_info *) data;
1942e4b17023SJohn Marino omp_context *ctx = (omp_context *) wi->info;
1943e4b17023SJohn Marino tree t = *tp;
1944e4b17023SJohn Marino
1945e4b17023SJohn Marino switch (TREE_CODE (t))
1946e4b17023SJohn Marino {
1947e4b17023SJohn Marino case VAR_DECL:
1948e4b17023SJohn Marino case PARM_DECL:
1949e4b17023SJohn Marino case LABEL_DECL:
1950e4b17023SJohn Marino case RESULT_DECL:
1951e4b17023SJohn Marino if (ctx)
1952e4b17023SJohn Marino *tp = remap_decl (t, &ctx->cb);
1953e4b17023SJohn Marino break;
1954e4b17023SJohn Marino
1955e4b17023SJohn Marino default:
1956e4b17023SJohn Marino if (ctx && TYPE_P (t))
1957e4b17023SJohn Marino *tp = remap_type (t, &ctx->cb);
1958e4b17023SJohn Marino else if (!DECL_P (t))
1959e4b17023SJohn Marino {
1960e4b17023SJohn Marino *walk_subtrees = 1;
1961e4b17023SJohn Marino if (ctx)
1962e4b17023SJohn Marino {
1963e4b17023SJohn Marino tree tem = remap_type (TREE_TYPE (t), &ctx->cb);
1964e4b17023SJohn Marino if (tem != TREE_TYPE (t))
1965e4b17023SJohn Marino {
1966e4b17023SJohn Marino if (TREE_CODE (t) == INTEGER_CST)
1967e4b17023SJohn Marino *tp = build_int_cst_wide (tem,
1968e4b17023SJohn Marino TREE_INT_CST_LOW (t),
1969e4b17023SJohn Marino TREE_INT_CST_HIGH (t));
1970e4b17023SJohn Marino else
1971e4b17023SJohn Marino TREE_TYPE (t) = tem;
1972e4b17023SJohn Marino }
1973e4b17023SJohn Marino }
1974e4b17023SJohn Marino }
1975e4b17023SJohn Marino break;
1976e4b17023SJohn Marino }
1977e4b17023SJohn Marino
1978e4b17023SJohn Marino return NULL_TREE;
1979e4b17023SJohn Marino }
1980e4b17023SJohn Marino
1981e4b17023SJohn Marino
1982e4b17023SJohn Marino /* Helper function for scan_omp.
1983e4b17023SJohn Marino
1984e4b17023SJohn Marino Callback for walk_gimple_stmt used to scan for OpenMP directives in
1985e4b17023SJohn Marino the current statement in GSI. */
1986e4b17023SJohn Marino
1987e4b17023SJohn Marino static tree
scan_omp_1_stmt(gimple_stmt_iterator * gsi,bool * handled_ops_p,struct walk_stmt_info * wi)1988e4b17023SJohn Marino scan_omp_1_stmt (gimple_stmt_iterator *gsi, bool *handled_ops_p,
1989e4b17023SJohn Marino struct walk_stmt_info *wi)
1990e4b17023SJohn Marino {
1991e4b17023SJohn Marino gimple stmt = gsi_stmt (*gsi);
1992e4b17023SJohn Marino omp_context *ctx = (omp_context *) wi->info;
1993e4b17023SJohn Marino
1994e4b17023SJohn Marino if (gimple_has_location (stmt))
1995e4b17023SJohn Marino input_location = gimple_location (stmt);
1996e4b17023SJohn Marino
1997e4b17023SJohn Marino /* Check the OpenMP nesting restrictions. */
1998e4b17023SJohn Marino if (ctx != NULL)
1999e4b17023SJohn Marino {
2000e4b17023SJohn Marino bool remove = false;
2001e4b17023SJohn Marino if (is_gimple_omp (stmt))
2002e4b17023SJohn Marino remove = !check_omp_nesting_restrictions (stmt, ctx);
2003e4b17023SJohn Marino else if (is_gimple_call (stmt))
2004e4b17023SJohn Marino {
2005e4b17023SJohn Marino tree fndecl = gimple_call_fndecl (stmt);
2006e4b17023SJohn Marino if (fndecl && DECL_BUILT_IN_CLASS (fndecl) == BUILT_IN_NORMAL
2007e4b17023SJohn Marino && DECL_FUNCTION_CODE (fndecl) == BUILT_IN_GOMP_BARRIER)
2008e4b17023SJohn Marino remove = !check_omp_nesting_restrictions (stmt, ctx);
2009e4b17023SJohn Marino }
2010e4b17023SJohn Marino if (remove)
2011e4b17023SJohn Marino {
2012e4b17023SJohn Marino stmt = gimple_build_nop ();
2013e4b17023SJohn Marino gsi_replace (gsi, stmt, false);
2014e4b17023SJohn Marino }
2015e4b17023SJohn Marino }
2016e4b17023SJohn Marino
2017e4b17023SJohn Marino *handled_ops_p = true;
2018e4b17023SJohn Marino
2019e4b17023SJohn Marino switch (gimple_code (stmt))
2020e4b17023SJohn Marino {
2021e4b17023SJohn Marino case GIMPLE_OMP_PARALLEL:
2022e4b17023SJohn Marino taskreg_nesting_level++;
2023e4b17023SJohn Marino scan_omp_parallel (gsi, ctx);
2024e4b17023SJohn Marino taskreg_nesting_level--;
2025e4b17023SJohn Marino break;
2026e4b17023SJohn Marino
2027e4b17023SJohn Marino case GIMPLE_OMP_TASK:
2028e4b17023SJohn Marino taskreg_nesting_level++;
2029e4b17023SJohn Marino scan_omp_task (gsi, ctx);
2030e4b17023SJohn Marino taskreg_nesting_level--;
2031e4b17023SJohn Marino break;
2032e4b17023SJohn Marino
2033e4b17023SJohn Marino case GIMPLE_OMP_FOR:
2034e4b17023SJohn Marino scan_omp_for (stmt, ctx);
2035e4b17023SJohn Marino break;
2036e4b17023SJohn Marino
2037e4b17023SJohn Marino case GIMPLE_OMP_SECTIONS:
2038e4b17023SJohn Marino scan_omp_sections (stmt, ctx);
2039e4b17023SJohn Marino break;
2040e4b17023SJohn Marino
2041e4b17023SJohn Marino case GIMPLE_OMP_SINGLE:
2042e4b17023SJohn Marino scan_omp_single (stmt, ctx);
2043e4b17023SJohn Marino break;
2044e4b17023SJohn Marino
2045e4b17023SJohn Marino case GIMPLE_OMP_SECTION:
2046e4b17023SJohn Marino case GIMPLE_OMP_MASTER:
2047e4b17023SJohn Marino case GIMPLE_OMP_ORDERED:
2048e4b17023SJohn Marino case GIMPLE_OMP_CRITICAL:
2049e4b17023SJohn Marino ctx = new_omp_context (stmt, ctx);
2050e4b17023SJohn Marino scan_omp (gimple_omp_body (stmt), ctx);
2051e4b17023SJohn Marino break;
2052e4b17023SJohn Marino
2053e4b17023SJohn Marino case GIMPLE_BIND:
2054e4b17023SJohn Marino {
2055e4b17023SJohn Marino tree var;
2056e4b17023SJohn Marino
2057e4b17023SJohn Marino *handled_ops_p = false;
2058e4b17023SJohn Marino if (ctx)
2059e4b17023SJohn Marino for (var = gimple_bind_vars (stmt); var ; var = DECL_CHAIN (var))
2060e4b17023SJohn Marino insert_decl_map (&ctx->cb, var, var);
2061e4b17023SJohn Marino }
2062e4b17023SJohn Marino break;
2063e4b17023SJohn Marino default:
2064e4b17023SJohn Marino *handled_ops_p = false;
2065e4b17023SJohn Marino break;
2066e4b17023SJohn Marino }
2067e4b17023SJohn Marino
2068e4b17023SJohn Marino return NULL_TREE;
2069e4b17023SJohn Marino }
2070e4b17023SJohn Marino
2071e4b17023SJohn Marino
2072e4b17023SJohn Marino /* Scan all the statements starting at the current statement. CTX
2073e4b17023SJohn Marino contains context information about the OpenMP directives and
2074e4b17023SJohn Marino clauses found during the scan. */
2075e4b17023SJohn Marino
2076e4b17023SJohn Marino static void
scan_omp(gimple_seq body,omp_context * ctx)2077e4b17023SJohn Marino scan_omp (gimple_seq body, omp_context *ctx)
2078e4b17023SJohn Marino {
2079e4b17023SJohn Marino location_t saved_location;
2080e4b17023SJohn Marino struct walk_stmt_info wi;
2081e4b17023SJohn Marino
2082e4b17023SJohn Marino memset (&wi, 0, sizeof (wi));
2083e4b17023SJohn Marino wi.info = ctx;
2084e4b17023SJohn Marino wi.want_locations = true;
2085e4b17023SJohn Marino
2086e4b17023SJohn Marino saved_location = input_location;
2087e4b17023SJohn Marino walk_gimple_seq (body, scan_omp_1_stmt, scan_omp_1_op, &wi);
2088e4b17023SJohn Marino input_location = saved_location;
2089e4b17023SJohn Marino }
2090e4b17023SJohn Marino
2091e4b17023SJohn Marino /* Re-gimplification and code generation routines. */
2092e4b17023SJohn Marino
2093e4b17023SJohn Marino /* Build a call to GOMP_barrier. */
2094e4b17023SJohn Marino
2095e4b17023SJohn Marino static tree
build_omp_barrier(void)2096e4b17023SJohn Marino build_omp_barrier (void)
2097e4b17023SJohn Marino {
2098e4b17023SJohn Marino return build_call_expr (builtin_decl_explicit (BUILT_IN_GOMP_BARRIER), 0);
2099e4b17023SJohn Marino }
2100e4b17023SJohn Marino
2101e4b17023SJohn Marino /* If a context was created for STMT when it was scanned, return it. */
2102e4b17023SJohn Marino
2103e4b17023SJohn Marino static omp_context *
maybe_lookup_ctx(gimple stmt)2104e4b17023SJohn Marino maybe_lookup_ctx (gimple stmt)
2105e4b17023SJohn Marino {
2106e4b17023SJohn Marino splay_tree_node n;
2107e4b17023SJohn Marino n = splay_tree_lookup (all_contexts, (splay_tree_key) stmt);
2108e4b17023SJohn Marino return n ? (omp_context *) n->value : NULL;
2109e4b17023SJohn Marino }
2110e4b17023SJohn Marino
2111e4b17023SJohn Marino
2112e4b17023SJohn Marino /* Find the mapping for DECL in CTX or the immediately enclosing
2113e4b17023SJohn Marino context that has a mapping for DECL.
2114e4b17023SJohn Marino
2115e4b17023SJohn Marino If CTX is a nested parallel directive, we may have to use the decl
2116e4b17023SJohn Marino mappings created in CTX's parent context. Suppose that we have the
2117e4b17023SJohn Marino following parallel nesting (variable UIDs showed for clarity):
2118e4b17023SJohn Marino
2119e4b17023SJohn Marino iD.1562 = 0;
2120e4b17023SJohn Marino #omp parallel shared(iD.1562) -> outer parallel
2121e4b17023SJohn Marino iD.1562 = iD.1562 + 1;
2122e4b17023SJohn Marino
2123e4b17023SJohn Marino #omp parallel shared (iD.1562) -> inner parallel
2124e4b17023SJohn Marino iD.1562 = iD.1562 - 1;
2125e4b17023SJohn Marino
2126e4b17023SJohn Marino Each parallel structure will create a distinct .omp_data_s structure
2127e4b17023SJohn Marino for copying iD.1562 in/out of the directive:
2128e4b17023SJohn Marino
2129e4b17023SJohn Marino outer parallel .omp_data_s.1.i -> iD.1562
2130e4b17023SJohn Marino inner parallel .omp_data_s.2.i -> iD.1562
2131e4b17023SJohn Marino
2132e4b17023SJohn Marino A shared variable mapping will produce a copy-out operation before
2133e4b17023SJohn Marino the parallel directive and a copy-in operation after it. So, in
2134e4b17023SJohn Marino this case we would have:
2135e4b17023SJohn Marino
2136e4b17023SJohn Marino iD.1562 = 0;
2137e4b17023SJohn Marino .omp_data_o.1.i = iD.1562;
2138e4b17023SJohn Marino #omp parallel shared(iD.1562) -> outer parallel
2139e4b17023SJohn Marino .omp_data_i.1 = &.omp_data_o.1
2140e4b17023SJohn Marino .omp_data_i.1->i = .omp_data_i.1->i + 1;
2141e4b17023SJohn Marino
2142e4b17023SJohn Marino .omp_data_o.2.i = iD.1562; -> **
2143e4b17023SJohn Marino #omp parallel shared(iD.1562) -> inner parallel
2144e4b17023SJohn Marino .omp_data_i.2 = &.omp_data_o.2
2145e4b17023SJohn Marino .omp_data_i.2->i = .omp_data_i.2->i - 1;
2146e4b17023SJohn Marino
2147e4b17023SJohn Marino
2148e4b17023SJohn Marino ** This is a problem. The symbol iD.1562 cannot be referenced
2149e4b17023SJohn Marino inside the body of the outer parallel region. But since we are
2150e4b17023SJohn Marino emitting this copy operation while expanding the inner parallel
2151e4b17023SJohn Marino directive, we need to access the CTX structure of the outer
2152e4b17023SJohn Marino parallel directive to get the correct mapping:
2153e4b17023SJohn Marino
2154e4b17023SJohn Marino .omp_data_o.2.i = .omp_data_i.1->i
2155e4b17023SJohn Marino
2156e4b17023SJohn Marino Since there may be other workshare or parallel directives enclosing
2157e4b17023SJohn Marino the parallel directive, it may be necessary to walk up the context
2158e4b17023SJohn Marino parent chain. This is not a problem in general because nested
2159e4b17023SJohn Marino parallelism happens only rarely. */
2160e4b17023SJohn Marino
2161e4b17023SJohn Marino static tree
lookup_decl_in_outer_ctx(tree decl,omp_context * ctx)2162e4b17023SJohn Marino lookup_decl_in_outer_ctx (tree decl, omp_context *ctx)
2163e4b17023SJohn Marino {
2164e4b17023SJohn Marino tree t;
2165e4b17023SJohn Marino omp_context *up;
2166e4b17023SJohn Marino
2167e4b17023SJohn Marino for (up = ctx->outer, t = NULL; up && t == NULL; up = up->outer)
2168e4b17023SJohn Marino t = maybe_lookup_decl (decl, up);
2169e4b17023SJohn Marino
2170e4b17023SJohn Marino gcc_assert (!ctx->is_nested || t || is_global_var (decl));
2171e4b17023SJohn Marino
2172e4b17023SJohn Marino return t ? t : decl;
2173e4b17023SJohn Marino }
2174e4b17023SJohn Marino
2175e4b17023SJohn Marino
2176e4b17023SJohn Marino /* Similar to lookup_decl_in_outer_ctx, but return DECL if not found
2177e4b17023SJohn Marino in outer contexts. */
2178e4b17023SJohn Marino
2179e4b17023SJohn Marino static tree
maybe_lookup_decl_in_outer_ctx(tree decl,omp_context * ctx)2180e4b17023SJohn Marino maybe_lookup_decl_in_outer_ctx (tree decl, omp_context *ctx)
2181e4b17023SJohn Marino {
2182e4b17023SJohn Marino tree t = NULL;
2183e4b17023SJohn Marino omp_context *up;
2184e4b17023SJohn Marino
2185e4b17023SJohn Marino for (up = ctx->outer, t = NULL; up && t == NULL; up = up->outer)
2186e4b17023SJohn Marino t = maybe_lookup_decl (decl, up);
2187e4b17023SJohn Marino
2188e4b17023SJohn Marino return t ? t : decl;
2189e4b17023SJohn Marino }
2190e4b17023SJohn Marino
2191e4b17023SJohn Marino
2192e4b17023SJohn Marino /* Construct the initialization value for reduction CLAUSE. */
2193e4b17023SJohn Marino
2194e4b17023SJohn Marino tree
omp_reduction_init(tree clause,tree type)2195e4b17023SJohn Marino omp_reduction_init (tree clause, tree type)
2196e4b17023SJohn Marino {
2197e4b17023SJohn Marino location_t loc = OMP_CLAUSE_LOCATION (clause);
2198e4b17023SJohn Marino switch (OMP_CLAUSE_REDUCTION_CODE (clause))
2199e4b17023SJohn Marino {
2200e4b17023SJohn Marino case PLUS_EXPR:
2201e4b17023SJohn Marino case MINUS_EXPR:
2202e4b17023SJohn Marino case BIT_IOR_EXPR:
2203e4b17023SJohn Marino case BIT_XOR_EXPR:
2204e4b17023SJohn Marino case TRUTH_OR_EXPR:
2205e4b17023SJohn Marino case TRUTH_ORIF_EXPR:
2206e4b17023SJohn Marino case TRUTH_XOR_EXPR:
2207e4b17023SJohn Marino case NE_EXPR:
2208e4b17023SJohn Marino return build_zero_cst (type);
2209e4b17023SJohn Marino
2210e4b17023SJohn Marino case MULT_EXPR:
2211e4b17023SJohn Marino case TRUTH_AND_EXPR:
2212e4b17023SJohn Marino case TRUTH_ANDIF_EXPR:
2213e4b17023SJohn Marino case EQ_EXPR:
2214e4b17023SJohn Marino return fold_convert_loc (loc, type, integer_one_node);
2215e4b17023SJohn Marino
2216e4b17023SJohn Marino case BIT_AND_EXPR:
2217e4b17023SJohn Marino return fold_convert_loc (loc, type, integer_minus_one_node);
2218e4b17023SJohn Marino
2219e4b17023SJohn Marino case MAX_EXPR:
2220e4b17023SJohn Marino if (SCALAR_FLOAT_TYPE_P (type))
2221e4b17023SJohn Marino {
2222e4b17023SJohn Marino REAL_VALUE_TYPE max, min;
2223e4b17023SJohn Marino if (HONOR_INFINITIES (TYPE_MODE (type)))
2224e4b17023SJohn Marino {
2225e4b17023SJohn Marino real_inf (&max);
2226e4b17023SJohn Marino real_arithmetic (&min, NEGATE_EXPR, &max, NULL);
2227e4b17023SJohn Marino }
2228e4b17023SJohn Marino else
2229e4b17023SJohn Marino real_maxval (&min, 1, TYPE_MODE (type));
2230e4b17023SJohn Marino return build_real (type, min);
2231e4b17023SJohn Marino }
2232e4b17023SJohn Marino else
2233e4b17023SJohn Marino {
2234e4b17023SJohn Marino gcc_assert (INTEGRAL_TYPE_P (type));
2235e4b17023SJohn Marino return TYPE_MIN_VALUE (type);
2236e4b17023SJohn Marino }
2237e4b17023SJohn Marino
2238e4b17023SJohn Marino case MIN_EXPR:
2239e4b17023SJohn Marino if (SCALAR_FLOAT_TYPE_P (type))
2240e4b17023SJohn Marino {
2241e4b17023SJohn Marino REAL_VALUE_TYPE max;
2242e4b17023SJohn Marino if (HONOR_INFINITIES (TYPE_MODE (type)))
2243e4b17023SJohn Marino real_inf (&max);
2244e4b17023SJohn Marino else
2245e4b17023SJohn Marino real_maxval (&max, 0, TYPE_MODE (type));
2246e4b17023SJohn Marino return build_real (type, max);
2247e4b17023SJohn Marino }
2248e4b17023SJohn Marino else
2249e4b17023SJohn Marino {
2250e4b17023SJohn Marino gcc_assert (INTEGRAL_TYPE_P (type));
2251e4b17023SJohn Marino return TYPE_MAX_VALUE (type);
2252e4b17023SJohn Marino }
2253e4b17023SJohn Marino
2254e4b17023SJohn Marino default:
2255e4b17023SJohn Marino gcc_unreachable ();
2256e4b17023SJohn Marino }
2257e4b17023SJohn Marino }
2258e4b17023SJohn Marino
2259e4b17023SJohn Marino /* Generate code to implement the input clauses, FIRSTPRIVATE and COPYIN,
2260e4b17023SJohn Marino from the receiver (aka child) side and initializers for REFERENCE_TYPE
2261e4b17023SJohn Marino private variables. Initialization statements go in ILIST, while calls
2262e4b17023SJohn Marino to destructors go in DLIST. */
2263e4b17023SJohn Marino
2264e4b17023SJohn Marino static void
lower_rec_input_clauses(tree clauses,gimple_seq * ilist,gimple_seq * dlist,omp_context * ctx)2265e4b17023SJohn Marino lower_rec_input_clauses (tree clauses, gimple_seq *ilist, gimple_seq *dlist,
2266e4b17023SJohn Marino omp_context *ctx)
2267e4b17023SJohn Marino {
2268e4b17023SJohn Marino gimple_stmt_iterator diter;
2269e4b17023SJohn Marino tree c, dtor, copyin_seq, x, ptr;
2270e4b17023SJohn Marino bool copyin_by_ref = false;
2271e4b17023SJohn Marino bool lastprivate_firstprivate = false;
2272e4b17023SJohn Marino int pass;
2273e4b17023SJohn Marino
2274e4b17023SJohn Marino *dlist = gimple_seq_alloc ();
2275e4b17023SJohn Marino diter = gsi_start (*dlist);
2276e4b17023SJohn Marino copyin_seq = NULL;
2277e4b17023SJohn Marino
2278e4b17023SJohn Marino /* Do all the fixed sized types in the first pass, and the variable sized
2279e4b17023SJohn Marino types in the second pass. This makes sure that the scalar arguments to
2280e4b17023SJohn Marino the variable sized types are processed before we use them in the
2281e4b17023SJohn Marino variable sized operations. */
2282e4b17023SJohn Marino for (pass = 0; pass < 2; ++pass)
2283e4b17023SJohn Marino {
2284e4b17023SJohn Marino for (c = clauses; c ; c = OMP_CLAUSE_CHAIN (c))
2285e4b17023SJohn Marino {
2286e4b17023SJohn Marino enum omp_clause_code c_kind = OMP_CLAUSE_CODE (c);
2287e4b17023SJohn Marino tree var, new_var;
2288e4b17023SJohn Marino bool by_ref;
2289e4b17023SJohn Marino location_t clause_loc = OMP_CLAUSE_LOCATION (c);
2290e4b17023SJohn Marino
2291e4b17023SJohn Marino switch (c_kind)
2292e4b17023SJohn Marino {
2293e4b17023SJohn Marino case OMP_CLAUSE_PRIVATE:
2294e4b17023SJohn Marino if (OMP_CLAUSE_PRIVATE_DEBUG (c))
2295e4b17023SJohn Marino continue;
2296e4b17023SJohn Marino break;
2297e4b17023SJohn Marino case OMP_CLAUSE_SHARED:
2298e4b17023SJohn Marino if (maybe_lookup_decl (OMP_CLAUSE_DECL (c), ctx) == NULL)
2299e4b17023SJohn Marino {
2300e4b17023SJohn Marino gcc_assert (is_global_var (OMP_CLAUSE_DECL (c)));
2301e4b17023SJohn Marino continue;
2302e4b17023SJohn Marino }
2303e4b17023SJohn Marino case OMP_CLAUSE_FIRSTPRIVATE:
2304e4b17023SJohn Marino case OMP_CLAUSE_COPYIN:
2305e4b17023SJohn Marino case OMP_CLAUSE_REDUCTION:
2306e4b17023SJohn Marino break;
2307e4b17023SJohn Marino case OMP_CLAUSE_LASTPRIVATE:
2308e4b17023SJohn Marino if (OMP_CLAUSE_LASTPRIVATE_FIRSTPRIVATE (c))
2309e4b17023SJohn Marino {
2310e4b17023SJohn Marino lastprivate_firstprivate = true;
2311e4b17023SJohn Marino if (pass != 0)
2312e4b17023SJohn Marino continue;
2313e4b17023SJohn Marino }
2314e4b17023SJohn Marino break;
2315e4b17023SJohn Marino default:
2316e4b17023SJohn Marino continue;
2317e4b17023SJohn Marino }
2318e4b17023SJohn Marino
2319e4b17023SJohn Marino new_var = var = OMP_CLAUSE_DECL (c);
2320e4b17023SJohn Marino if (c_kind != OMP_CLAUSE_COPYIN)
2321e4b17023SJohn Marino new_var = lookup_decl (var, ctx);
2322e4b17023SJohn Marino
2323e4b17023SJohn Marino if (c_kind == OMP_CLAUSE_SHARED || c_kind == OMP_CLAUSE_COPYIN)
2324e4b17023SJohn Marino {
2325e4b17023SJohn Marino if (pass != 0)
2326e4b17023SJohn Marino continue;
2327e4b17023SJohn Marino }
2328e4b17023SJohn Marino else if (is_variable_sized (var))
2329e4b17023SJohn Marino {
2330e4b17023SJohn Marino /* For variable sized types, we need to allocate the
2331e4b17023SJohn Marino actual storage here. Call alloca and store the
2332e4b17023SJohn Marino result in the pointer decl that we created elsewhere. */
2333e4b17023SJohn Marino if (pass == 0)
2334e4b17023SJohn Marino continue;
2335e4b17023SJohn Marino
2336e4b17023SJohn Marino if (c_kind != OMP_CLAUSE_FIRSTPRIVATE || !is_task_ctx (ctx))
2337e4b17023SJohn Marino {
2338e4b17023SJohn Marino gimple stmt;
2339e4b17023SJohn Marino tree tmp, atmp;
2340e4b17023SJohn Marino
2341e4b17023SJohn Marino ptr = DECL_VALUE_EXPR (new_var);
2342e4b17023SJohn Marino gcc_assert (TREE_CODE (ptr) == INDIRECT_REF);
2343e4b17023SJohn Marino ptr = TREE_OPERAND (ptr, 0);
2344e4b17023SJohn Marino gcc_assert (DECL_P (ptr));
2345e4b17023SJohn Marino x = TYPE_SIZE_UNIT (TREE_TYPE (new_var));
2346e4b17023SJohn Marino
2347e4b17023SJohn Marino /* void *tmp = __builtin_alloca */
2348e4b17023SJohn Marino atmp = builtin_decl_explicit (BUILT_IN_ALLOCA);
2349e4b17023SJohn Marino stmt = gimple_build_call (atmp, 1, x);
2350e4b17023SJohn Marino tmp = create_tmp_var_raw (ptr_type_node, NULL);
2351e4b17023SJohn Marino gimple_add_tmp_var (tmp);
2352e4b17023SJohn Marino gimple_call_set_lhs (stmt, tmp);
2353e4b17023SJohn Marino
2354e4b17023SJohn Marino gimple_seq_add_stmt (ilist, stmt);
2355e4b17023SJohn Marino
2356e4b17023SJohn Marino x = fold_convert_loc (clause_loc, TREE_TYPE (ptr), tmp);
2357e4b17023SJohn Marino gimplify_assign (ptr, x, ilist);
2358e4b17023SJohn Marino }
2359e4b17023SJohn Marino }
2360e4b17023SJohn Marino else if (is_reference (var))
2361e4b17023SJohn Marino {
2362e4b17023SJohn Marino /* For references that are being privatized for Fortran,
2363e4b17023SJohn Marino allocate new backing storage for the new pointer
2364e4b17023SJohn Marino variable. This allows us to avoid changing all the
2365e4b17023SJohn Marino code that expects a pointer to something that expects
2366e4b17023SJohn Marino a direct variable. Note that this doesn't apply to
2367e4b17023SJohn Marino C++, since reference types are disallowed in data
2368e4b17023SJohn Marino sharing clauses there, except for NRV optimized
2369e4b17023SJohn Marino return values. */
2370e4b17023SJohn Marino if (pass == 0)
2371e4b17023SJohn Marino continue;
2372e4b17023SJohn Marino
2373e4b17023SJohn Marino x = TYPE_SIZE_UNIT (TREE_TYPE (TREE_TYPE (new_var)));
2374e4b17023SJohn Marino if (c_kind == OMP_CLAUSE_FIRSTPRIVATE && is_task_ctx (ctx))
2375e4b17023SJohn Marino {
2376e4b17023SJohn Marino x = build_receiver_ref (var, false, ctx);
2377e4b17023SJohn Marino x = build_fold_addr_expr_loc (clause_loc, x);
2378e4b17023SJohn Marino }
2379e4b17023SJohn Marino else if (TREE_CONSTANT (x))
2380e4b17023SJohn Marino {
2381e4b17023SJohn Marino const char *name = NULL;
2382e4b17023SJohn Marino if (DECL_NAME (var))
2383e4b17023SJohn Marino name = IDENTIFIER_POINTER (DECL_NAME (new_var));
2384e4b17023SJohn Marino
2385e4b17023SJohn Marino x = create_tmp_var_raw (TREE_TYPE (TREE_TYPE (new_var)),
2386e4b17023SJohn Marino name);
2387e4b17023SJohn Marino gimple_add_tmp_var (x);
2388e4b17023SJohn Marino TREE_ADDRESSABLE (x) = 1;
2389e4b17023SJohn Marino x = build_fold_addr_expr_loc (clause_loc, x);
2390e4b17023SJohn Marino }
2391e4b17023SJohn Marino else
2392e4b17023SJohn Marino {
2393e4b17023SJohn Marino tree atmp = builtin_decl_explicit (BUILT_IN_ALLOCA);
2394e4b17023SJohn Marino x = build_call_expr_loc (clause_loc, atmp, 1, x);
2395e4b17023SJohn Marino }
2396e4b17023SJohn Marino
2397e4b17023SJohn Marino x = fold_convert_loc (clause_loc, TREE_TYPE (new_var), x);
2398e4b17023SJohn Marino gimplify_assign (new_var, x, ilist);
2399e4b17023SJohn Marino
2400e4b17023SJohn Marino new_var = build_simple_mem_ref_loc (clause_loc, new_var);
2401e4b17023SJohn Marino }
2402e4b17023SJohn Marino else if (c_kind == OMP_CLAUSE_REDUCTION
2403e4b17023SJohn Marino && OMP_CLAUSE_REDUCTION_PLACEHOLDER (c))
2404e4b17023SJohn Marino {
2405e4b17023SJohn Marino if (pass == 0)
2406e4b17023SJohn Marino continue;
2407e4b17023SJohn Marino }
2408e4b17023SJohn Marino else if (pass != 0)
2409e4b17023SJohn Marino continue;
2410e4b17023SJohn Marino
2411e4b17023SJohn Marino switch (OMP_CLAUSE_CODE (c))
2412e4b17023SJohn Marino {
2413e4b17023SJohn Marino case OMP_CLAUSE_SHARED:
2414e4b17023SJohn Marino /* Shared global vars are just accessed directly. */
2415e4b17023SJohn Marino if (is_global_var (new_var))
2416e4b17023SJohn Marino break;
2417e4b17023SJohn Marino /* Set up the DECL_VALUE_EXPR for shared variables now. This
2418e4b17023SJohn Marino needs to be delayed until after fixup_child_record_type so
2419e4b17023SJohn Marino that we get the correct type during the dereference. */
2420e4b17023SJohn Marino by_ref = use_pointer_for_field (var, ctx);
2421e4b17023SJohn Marino x = build_receiver_ref (var, by_ref, ctx);
2422e4b17023SJohn Marino SET_DECL_VALUE_EXPR (new_var, x);
2423e4b17023SJohn Marino DECL_HAS_VALUE_EXPR_P (new_var) = 1;
2424e4b17023SJohn Marino
2425e4b17023SJohn Marino /* ??? If VAR is not passed by reference, and the variable
2426e4b17023SJohn Marino hasn't been initialized yet, then we'll get a warning for
2427e4b17023SJohn Marino the store into the omp_data_s structure. Ideally, we'd be
2428e4b17023SJohn Marino able to notice this and not store anything at all, but
2429e4b17023SJohn Marino we're generating code too early. Suppress the warning. */
2430e4b17023SJohn Marino if (!by_ref)
2431e4b17023SJohn Marino TREE_NO_WARNING (var) = 1;
2432e4b17023SJohn Marino break;
2433e4b17023SJohn Marino
2434e4b17023SJohn Marino case OMP_CLAUSE_LASTPRIVATE:
2435e4b17023SJohn Marino if (OMP_CLAUSE_LASTPRIVATE_FIRSTPRIVATE (c))
2436e4b17023SJohn Marino break;
2437e4b17023SJohn Marino /* FALLTHRU */
2438e4b17023SJohn Marino
2439e4b17023SJohn Marino case OMP_CLAUSE_PRIVATE:
2440e4b17023SJohn Marino if (OMP_CLAUSE_CODE (c) != OMP_CLAUSE_PRIVATE)
2441e4b17023SJohn Marino x = build_outer_var_ref (var, ctx);
2442e4b17023SJohn Marino else if (OMP_CLAUSE_PRIVATE_OUTER_REF (c))
2443e4b17023SJohn Marino {
2444e4b17023SJohn Marino if (is_task_ctx (ctx))
2445e4b17023SJohn Marino x = build_receiver_ref (var, false, ctx);
2446e4b17023SJohn Marino else
2447e4b17023SJohn Marino x = build_outer_var_ref (var, ctx);
2448e4b17023SJohn Marino }
2449e4b17023SJohn Marino else
2450e4b17023SJohn Marino x = NULL;
2451e4b17023SJohn Marino x = lang_hooks.decls.omp_clause_default_ctor (c, new_var, x);
2452e4b17023SJohn Marino if (x)
2453e4b17023SJohn Marino gimplify_and_add (x, ilist);
2454e4b17023SJohn Marino /* FALLTHRU */
2455e4b17023SJohn Marino
2456e4b17023SJohn Marino do_dtor:
2457e4b17023SJohn Marino x = lang_hooks.decls.omp_clause_dtor (c, new_var);
2458e4b17023SJohn Marino if (x)
2459e4b17023SJohn Marino {
2460e4b17023SJohn Marino gimple_seq tseq = NULL;
2461e4b17023SJohn Marino
2462e4b17023SJohn Marino dtor = x;
2463e4b17023SJohn Marino gimplify_stmt (&dtor, &tseq);
2464e4b17023SJohn Marino gsi_insert_seq_before (&diter, tseq, GSI_SAME_STMT);
2465e4b17023SJohn Marino }
2466e4b17023SJohn Marino break;
2467e4b17023SJohn Marino
2468e4b17023SJohn Marino case OMP_CLAUSE_FIRSTPRIVATE:
2469e4b17023SJohn Marino if (is_task_ctx (ctx))
2470e4b17023SJohn Marino {
2471e4b17023SJohn Marino if (is_reference (var) || is_variable_sized (var))
2472e4b17023SJohn Marino goto do_dtor;
2473e4b17023SJohn Marino else if (is_global_var (maybe_lookup_decl_in_outer_ctx (var,
2474e4b17023SJohn Marino ctx))
2475e4b17023SJohn Marino || use_pointer_for_field (var, NULL))
2476e4b17023SJohn Marino {
2477e4b17023SJohn Marino x = build_receiver_ref (var, false, ctx);
2478e4b17023SJohn Marino SET_DECL_VALUE_EXPR (new_var, x);
2479e4b17023SJohn Marino DECL_HAS_VALUE_EXPR_P (new_var) = 1;
2480e4b17023SJohn Marino goto do_dtor;
2481e4b17023SJohn Marino }
2482e4b17023SJohn Marino }
2483e4b17023SJohn Marino x = build_outer_var_ref (var, ctx);
2484e4b17023SJohn Marino x = lang_hooks.decls.omp_clause_copy_ctor (c, new_var, x);
2485e4b17023SJohn Marino gimplify_and_add (x, ilist);
2486e4b17023SJohn Marino goto do_dtor;
2487e4b17023SJohn Marino break;
2488e4b17023SJohn Marino
2489e4b17023SJohn Marino case OMP_CLAUSE_COPYIN:
2490e4b17023SJohn Marino by_ref = use_pointer_for_field (var, NULL);
2491e4b17023SJohn Marino x = build_receiver_ref (var, by_ref, ctx);
2492e4b17023SJohn Marino x = lang_hooks.decls.omp_clause_assign_op (c, new_var, x);
2493e4b17023SJohn Marino append_to_statement_list (x, ©in_seq);
2494e4b17023SJohn Marino copyin_by_ref |= by_ref;
2495e4b17023SJohn Marino break;
2496e4b17023SJohn Marino
2497e4b17023SJohn Marino case OMP_CLAUSE_REDUCTION:
2498e4b17023SJohn Marino if (OMP_CLAUSE_REDUCTION_PLACEHOLDER (c))
2499e4b17023SJohn Marino {
2500e4b17023SJohn Marino tree placeholder = OMP_CLAUSE_REDUCTION_PLACEHOLDER (c);
2501e4b17023SJohn Marino x = build_outer_var_ref (var, ctx);
2502e4b17023SJohn Marino
2503e4b17023SJohn Marino if (is_reference (var))
2504e4b17023SJohn Marino x = build_fold_addr_expr_loc (clause_loc, x);
2505e4b17023SJohn Marino SET_DECL_VALUE_EXPR (placeholder, x);
2506e4b17023SJohn Marino DECL_HAS_VALUE_EXPR_P (placeholder) = 1;
2507e4b17023SJohn Marino lower_omp (OMP_CLAUSE_REDUCTION_GIMPLE_INIT (c), ctx);
2508e4b17023SJohn Marino gimple_seq_add_seq (ilist,
2509e4b17023SJohn Marino OMP_CLAUSE_REDUCTION_GIMPLE_INIT (c));
2510e4b17023SJohn Marino OMP_CLAUSE_REDUCTION_GIMPLE_INIT (c) = NULL;
2511e4b17023SJohn Marino DECL_HAS_VALUE_EXPR_P (placeholder) = 0;
2512e4b17023SJohn Marino }
2513e4b17023SJohn Marino else
2514e4b17023SJohn Marino {
2515e4b17023SJohn Marino x = omp_reduction_init (c, TREE_TYPE (new_var));
2516e4b17023SJohn Marino gcc_assert (TREE_CODE (TREE_TYPE (new_var)) != ARRAY_TYPE);
2517e4b17023SJohn Marino gimplify_assign (new_var, x, ilist);
2518e4b17023SJohn Marino }
2519e4b17023SJohn Marino break;
2520e4b17023SJohn Marino
2521e4b17023SJohn Marino default:
2522e4b17023SJohn Marino gcc_unreachable ();
2523e4b17023SJohn Marino }
2524e4b17023SJohn Marino }
2525e4b17023SJohn Marino }
2526e4b17023SJohn Marino
2527e4b17023SJohn Marino /* The copyin sequence is not to be executed by the main thread, since
2528e4b17023SJohn Marino that would result in self-copies. Perhaps not visible to scalars,
2529e4b17023SJohn Marino but it certainly is to C++ operator=. */
2530e4b17023SJohn Marino if (copyin_seq)
2531e4b17023SJohn Marino {
2532e4b17023SJohn Marino x = build_call_expr (builtin_decl_explicit (BUILT_IN_OMP_GET_THREAD_NUM),
2533e4b17023SJohn Marino 0);
2534e4b17023SJohn Marino x = build2 (NE_EXPR, boolean_type_node, x,
2535e4b17023SJohn Marino build_int_cst (TREE_TYPE (x), 0));
2536e4b17023SJohn Marino x = build3 (COND_EXPR, void_type_node, x, copyin_seq, NULL);
2537e4b17023SJohn Marino gimplify_and_add (x, ilist);
2538e4b17023SJohn Marino }
2539e4b17023SJohn Marino
2540e4b17023SJohn Marino /* If any copyin variable is passed by reference, we must ensure the
2541e4b17023SJohn Marino master thread doesn't modify it before it is copied over in all
2542e4b17023SJohn Marino threads. Similarly for variables in both firstprivate and
2543e4b17023SJohn Marino lastprivate clauses we need to ensure the lastprivate copying
2544e4b17023SJohn Marino happens after firstprivate copying in all threads. */
2545e4b17023SJohn Marino if (copyin_by_ref || lastprivate_firstprivate)
2546e4b17023SJohn Marino gimplify_and_add (build_omp_barrier (), ilist);
2547e4b17023SJohn Marino }
2548e4b17023SJohn Marino
2549e4b17023SJohn Marino
2550e4b17023SJohn Marino /* Generate code to implement the LASTPRIVATE clauses. This is used for
2551e4b17023SJohn Marino both parallel and workshare constructs. PREDICATE may be NULL if it's
2552e4b17023SJohn Marino always true. */
2553e4b17023SJohn Marino
2554e4b17023SJohn Marino static void
lower_lastprivate_clauses(tree clauses,tree predicate,gimple_seq * stmt_list,omp_context * ctx)2555e4b17023SJohn Marino lower_lastprivate_clauses (tree clauses, tree predicate, gimple_seq *stmt_list,
2556e4b17023SJohn Marino omp_context *ctx)
2557e4b17023SJohn Marino {
2558e4b17023SJohn Marino tree x, c, label = NULL;
2559e4b17023SJohn Marino bool par_clauses = false;
2560e4b17023SJohn Marino
2561e4b17023SJohn Marino /* Early exit if there are no lastprivate clauses. */
2562e4b17023SJohn Marino clauses = find_omp_clause (clauses, OMP_CLAUSE_LASTPRIVATE);
2563e4b17023SJohn Marino if (clauses == NULL)
2564e4b17023SJohn Marino {
2565e4b17023SJohn Marino /* If this was a workshare clause, see if it had been combined
2566e4b17023SJohn Marino with its parallel. In that case, look for the clauses on the
2567e4b17023SJohn Marino parallel statement itself. */
2568e4b17023SJohn Marino if (is_parallel_ctx (ctx))
2569e4b17023SJohn Marino return;
2570e4b17023SJohn Marino
2571e4b17023SJohn Marino ctx = ctx->outer;
2572e4b17023SJohn Marino if (ctx == NULL || !is_parallel_ctx (ctx))
2573e4b17023SJohn Marino return;
2574e4b17023SJohn Marino
2575e4b17023SJohn Marino clauses = find_omp_clause (gimple_omp_parallel_clauses (ctx->stmt),
2576e4b17023SJohn Marino OMP_CLAUSE_LASTPRIVATE);
2577e4b17023SJohn Marino if (clauses == NULL)
2578e4b17023SJohn Marino return;
2579e4b17023SJohn Marino par_clauses = true;
2580e4b17023SJohn Marino }
2581e4b17023SJohn Marino
2582e4b17023SJohn Marino if (predicate)
2583e4b17023SJohn Marino {
2584e4b17023SJohn Marino gimple stmt;
2585e4b17023SJohn Marino tree label_true, arm1, arm2;
2586e4b17023SJohn Marino
2587e4b17023SJohn Marino label = create_artificial_label (UNKNOWN_LOCATION);
2588e4b17023SJohn Marino label_true = create_artificial_label (UNKNOWN_LOCATION);
2589e4b17023SJohn Marino arm1 = TREE_OPERAND (predicate, 0);
2590e4b17023SJohn Marino arm2 = TREE_OPERAND (predicate, 1);
2591e4b17023SJohn Marino gimplify_expr (&arm1, stmt_list, NULL, is_gimple_val, fb_rvalue);
2592e4b17023SJohn Marino gimplify_expr (&arm2, stmt_list, NULL, is_gimple_val, fb_rvalue);
2593e4b17023SJohn Marino stmt = gimple_build_cond (TREE_CODE (predicate), arm1, arm2,
2594e4b17023SJohn Marino label_true, label);
2595e4b17023SJohn Marino gimple_seq_add_stmt (stmt_list, stmt);
2596e4b17023SJohn Marino gimple_seq_add_stmt (stmt_list, gimple_build_label (label_true));
2597e4b17023SJohn Marino }
2598e4b17023SJohn Marino
2599e4b17023SJohn Marino for (c = clauses; c ;)
2600e4b17023SJohn Marino {
2601e4b17023SJohn Marino tree var, new_var;
2602e4b17023SJohn Marino location_t clause_loc = OMP_CLAUSE_LOCATION (c);
2603e4b17023SJohn Marino
2604e4b17023SJohn Marino if (OMP_CLAUSE_CODE (c) == OMP_CLAUSE_LASTPRIVATE)
2605e4b17023SJohn Marino {
2606e4b17023SJohn Marino var = OMP_CLAUSE_DECL (c);
2607e4b17023SJohn Marino new_var = lookup_decl (var, ctx);
2608e4b17023SJohn Marino
2609e4b17023SJohn Marino if (OMP_CLAUSE_LASTPRIVATE_GIMPLE_SEQ (c))
2610e4b17023SJohn Marino {
2611e4b17023SJohn Marino lower_omp (OMP_CLAUSE_LASTPRIVATE_GIMPLE_SEQ (c), ctx);
2612e4b17023SJohn Marino gimple_seq_add_seq (stmt_list,
2613e4b17023SJohn Marino OMP_CLAUSE_LASTPRIVATE_GIMPLE_SEQ (c));
2614e4b17023SJohn Marino }
2615e4b17023SJohn Marino OMP_CLAUSE_LASTPRIVATE_GIMPLE_SEQ (c) = NULL;
2616e4b17023SJohn Marino
2617e4b17023SJohn Marino x = build_outer_var_ref (var, ctx);
2618e4b17023SJohn Marino if (is_reference (var))
2619e4b17023SJohn Marino new_var = build_simple_mem_ref_loc (clause_loc, new_var);
2620e4b17023SJohn Marino x = lang_hooks.decls.omp_clause_assign_op (c, x, new_var);
2621e4b17023SJohn Marino gimplify_and_add (x, stmt_list);
2622e4b17023SJohn Marino }
2623e4b17023SJohn Marino c = OMP_CLAUSE_CHAIN (c);
2624e4b17023SJohn Marino if (c == NULL && !par_clauses)
2625e4b17023SJohn Marino {
2626e4b17023SJohn Marino /* If this was a workshare clause, see if it had been combined
2627e4b17023SJohn Marino with its parallel. In that case, continue looking for the
2628e4b17023SJohn Marino clauses also on the parallel statement itself. */
2629e4b17023SJohn Marino if (is_parallel_ctx (ctx))
2630e4b17023SJohn Marino break;
2631e4b17023SJohn Marino
2632e4b17023SJohn Marino ctx = ctx->outer;
2633e4b17023SJohn Marino if (ctx == NULL || !is_parallel_ctx (ctx))
2634e4b17023SJohn Marino break;
2635e4b17023SJohn Marino
2636e4b17023SJohn Marino c = find_omp_clause (gimple_omp_parallel_clauses (ctx->stmt),
2637e4b17023SJohn Marino OMP_CLAUSE_LASTPRIVATE);
2638e4b17023SJohn Marino par_clauses = true;
2639e4b17023SJohn Marino }
2640e4b17023SJohn Marino }
2641e4b17023SJohn Marino
2642e4b17023SJohn Marino if (label)
2643e4b17023SJohn Marino gimple_seq_add_stmt (stmt_list, gimple_build_label (label));
2644e4b17023SJohn Marino }
2645e4b17023SJohn Marino
2646e4b17023SJohn Marino
2647e4b17023SJohn Marino /* Generate code to implement the REDUCTION clauses. */
2648e4b17023SJohn Marino
2649e4b17023SJohn Marino static void
lower_reduction_clauses(tree clauses,gimple_seq * stmt_seqp,omp_context * ctx)2650e4b17023SJohn Marino lower_reduction_clauses (tree clauses, gimple_seq *stmt_seqp, omp_context *ctx)
2651e4b17023SJohn Marino {
2652e4b17023SJohn Marino gimple_seq sub_seq = NULL;
2653e4b17023SJohn Marino gimple stmt;
2654e4b17023SJohn Marino tree x, c;
2655e4b17023SJohn Marino int count = 0;
2656e4b17023SJohn Marino
2657e4b17023SJohn Marino /* First see if there is exactly one reduction clause. Use OMP_ATOMIC
2658e4b17023SJohn Marino update in that case, otherwise use a lock. */
2659e4b17023SJohn Marino for (c = clauses; c && count < 2; c = OMP_CLAUSE_CHAIN (c))
2660e4b17023SJohn Marino if (OMP_CLAUSE_CODE (c) == OMP_CLAUSE_REDUCTION)
2661e4b17023SJohn Marino {
2662e4b17023SJohn Marino if (OMP_CLAUSE_REDUCTION_PLACEHOLDER (c))
2663e4b17023SJohn Marino {
2664e4b17023SJohn Marino /* Never use OMP_ATOMIC for array reductions. */
2665e4b17023SJohn Marino count = -1;
2666e4b17023SJohn Marino break;
2667e4b17023SJohn Marino }
2668e4b17023SJohn Marino count++;
2669e4b17023SJohn Marino }
2670e4b17023SJohn Marino
2671e4b17023SJohn Marino if (count == 0)
2672e4b17023SJohn Marino return;
2673e4b17023SJohn Marino
2674e4b17023SJohn Marino for (c = clauses; c ; c = OMP_CLAUSE_CHAIN (c))
2675e4b17023SJohn Marino {
2676e4b17023SJohn Marino tree var, ref, new_var;
2677e4b17023SJohn Marino enum tree_code code;
2678e4b17023SJohn Marino location_t clause_loc = OMP_CLAUSE_LOCATION (c);
2679e4b17023SJohn Marino
2680e4b17023SJohn Marino if (OMP_CLAUSE_CODE (c) != OMP_CLAUSE_REDUCTION)
2681e4b17023SJohn Marino continue;
2682e4b17023SJohn Marino
2683e4b17023SJohn Marino var = OMP_CLAUSE_DECL (c);
2684e4b17023SJohn Marino new_var = lookup_decl (var, ctx);
2685e4b17023SJohn Marino if (is_reference (var))
2686e4b17023SJohn Marino new_var = build_simple_mem_ref_loc (clause_loc, new_var);
2687e4b17023SJohn Marino ref = build_outer_var_ref (var, ctx);
2688e4b17023SJohn Marino code = OMP_CLAUSE_REDUCTION_CODE (c);
2689e4b17023SJohn Marino
2690e4b17023SJohn Marino /* reduction(-:var) sums up the partial results, so it acts
2691e4b17023SJohn Marino identically to reduction(+:var). */
2692e4b17023SJohn Marino if (code == MINUS_EXPR)
2693e4b17023SJohn Marino code = PLUS_EXPR;
2694e4b17023SJohn Marino
2695e4b17023SJohn Marino if (count == 1)
2696e4b17023SJohn Marino {
2697e4b17023SJohn Marino tree addr = build_fold_addr_expr_loc (clause_loc, ref);
2698e4b17023SJohn Marino
2699e4b17023SJohn Marino addr = save_expr (addr);
2700e4b17023SJohn Marino ref = build1 (INDIRECT_REF, TREE_TYPE (TREE_TYPE (addr)), addr);
2701e4b17023SJohn Marino x = fold_build2_loc (clause_loc, code, TREE_TYPE (ref), ref, new_var);
2702e4b17023SJohn Marino x = build2 (OMP_ATOMIC, void_type_node, addr, x);
2703e4b17023SJohn Marino gimplify_and_add (x, stmt_seqp);
2704e4b17023SJohn Marino return;
2705e4b17023SJohn Marino }
2706e4b17023SJohn Marino
2707e4b17023SJohn Marino if (OMP_CLAUSE_REDUCTION_PLACEHOLDER (c))
2708e4b17023SJohn Marino {
2709e4b17023SJohn Marino tree placeholder = OMP_CLAUSE_REDUCTION_PLACEHOLDER (c);
2710e4b17023SJohn Marino
2711e4b17023SJohn Marino if (is_reference (var))
2712e4b17023SJohn Marino ref = build_fold_addr_expr_loc (clause_loc, ref);
2713e4b17023SJohn Marino SET_DECL_VALUE_EXPR (placeholder, ref);
2714e4b17023SJohn Marino DECL_HAS_VALUE_EXPR_P (placeholder) = 1;
2715e4b17023SJohn Marino lower_omp (OMP_CLAUSE_REDUCTION_GIMPLE_MERGE (c), ctx);
2716e4b17023SJohn Marino gimple_seq_add_seq (&sub_seq, OMP_CLAUSE_REDUCTION_GIMPLE_MERGE (c));
2717e4b17023SJohn Marino OMP_CLAUSE_REDUCTION_GIMPLE_MERGE (c) = NULL;
2718e4b17023SJohn Marino OMP_CLAUSE_REDUCTION_PLACEHOLDER (c) = NULL;
2719e4b17023SJohn Marino }
2720e4b17023SJohn Marino else
2721e4b17023SJohn Marino {
2722e4b17023SJohn Marino x = build2 (code, TREE_TYPE (ref), ref, new_var);
2723e4b17023SJohn Marino ref = build_outer_var_ref (var, ctx);
2724e4b17023SJohn Marino gimplify_assign (ref, x, &sub_seq);
2725e4b17023SJohn Marino }
2726e4b17023SJohn Marino }
2727e4b17023SJohn Marino
2728e4b17023SJohn Marino stmt = gimple_build_call (builtin_decl_explicit (BUILT_IN_GOMP_ATOMIC_START),
2729e4b17023SJohn Marino 0);
2730e4b17023SJohn Marino gimple_seq_add_stmt (stmt_seqp, stmt);
2731e4b17023SJohn Marino
2732e4b17023SJohn Marino gimple_seq_add_seq (stmt_seqp, sub_seq);
2733e4b17023SJohn Marino
2734e4b17023SJohn Marino stmt = gimple_build_call (builtin_decl_explicit (BUILT_IN_GOMP_ATOMIC_END),
2735e4b17023SJohn Marino 0);
2736e4b17023SJohn Marino gimple_seq_add_stmt (stmt_seqp, stmt);
2737e4b17023SJohn Marino }
2738e4b17023SJohn Marino
2739e4b17023SJohn Marino
2740e4b17023SJohn Marino /* Generate code to implement the COPYPRIVATE clauses. */
2741e4b17023SJohn Marino
2742e4b17023SJohn Marino static void
lower_copyprivate_clauses(tree clauses,gimple_seq * slist,gimple_seq * rlist,omp_context * ctx)2743e4b17023SJohn Marino lower_copyprivate_clauses (tree clauses, gimple_seq *slist, gimple_seq *rlist,
2744e4b17023SJohn Marino omp_context *ctx)
2745e4b17023SJohn Marino {
2746e4b17023SJohn Marino tree c;
2747e4b17023SJohn Marino
2748e4b17023SJohn Marino for (c = clauses; c ; c = OMP_CLAUSE_CHAIN (c))
2749e4b17023SJohn Marino {
2750e4b17023SJohn Marino tree var, new_var, ref, x;
2751e4b17023SJohn Marino bool by_ref;
2752e4b17023SJohn Marino location_t clause_loc = OMP_CLAUSE_LOCATION (c);
2753e4b17023SJohn Marino
2754e4b17023SJohn Marino if (OMP_CLAUSE_CODE (c) != OMP_CLAUSE_COPYPRIVATE)
2755e4b17023SJohn Marino continue;
2756e4b17023SJohn Marino
2757e4b17023SJohn Marino var = OMP_CLAUSE_DECL (c);
2758e4b17023SJohn Marino by_ref = use_pointer_for_field (var, NULL);
2759e4b17023SJohn Marino
2760e4b17023SJohn Marino ref = build_sender_ref (var, ctx);
2761e4b17023SJohn Marino x = new_var = lookup_decl_in_outer_ctx (var, ctx);
2762e4b17023SJohn Marino if (by_ref)
2763e4b17023SJohn Marino {
2764e4b17023SJohn Marino x = build_fold_addr_expr_loc (clause_loc, new_var);
2765e4b17023SJohn Marino x = fold_convert_loc (clause_loc, TREE_TYPE (ref), x);
2766e4b17023SJohn Marino }
2767e4b17023SJohn Marino gimplify_assign (ref, x, slist);
2768e4b17023SJohn Marino
2769e4b17023SJohn Marino ref = build_receiver_ref (var, false, ctx);
2770e4b17023SJohn Marino if (by_ref)
2771e4b17023SJohn Marino {
2772e4b17023SJohn Marino ref = fold_convert_loc (clause_loc,
2773e4b17023SJohn Marino build_pointer_type (TREE_TYPE (new_var)),
2774e4b17023SJohn Marino ref);
2775e4b17023SJohn Marino ref = build_fold_indirect_ref_loc (clause_loc, ref);
2776e4b17023SJohn Marino }
2777e4b17023SJohn Marino if (is_reference (var))
2778e4b17023SJohn Marino {
2779e4b17023SJohn Marino ref = fold_convert_loc (clause_loc, TREE_TYPE (new_var), ref);
2780e4b17023SJohn Marino ref = build_simple_mem_ref_loc (clause_loc, ref);
2781e4b17023SJohn Marino new_var = build_simple_mem_ref_loc (clause_loc, new_var);
2782e4b17023SJohn Marino }
2783e4b17023SJohn Marino x = lang_hooks.decls.omp_clause_assign_op (c, new_var, ref);
2784e4b17023SJohn Marino gimplify_and_add (x, rlist);
2785e4b17023SJohn Marino }
2786e4b17023SJohn Marino }
2787e4b17023SJohn Marino
2788e4b17023SJohn Marino
2789e4b17023SJohn Marino /* Generate code to implement the clauses, FIRSTPRIVATE, COPYIN, LASTPRIVATE,
2790e4b17023SJohn Marino and REDUCTION from the sender (aka parent) side. */
2791e4b17023SJohn Marino
2792e4b17023SJohn Marino static void
lower_send_clauses(tree clauses,gimple_seq * ilist,gimple_seq * olist,omp_context * ctx)2793e4b17023SJohn Marino lower_send_clauses (tree clauses, gimple_seq *ilist, gimple_seq *olist,
2794e4b17023SJohn Marino omp_context *ctx)
2795e4b17023SJohn Marino {
2796e4b17023SJohn Marino tree c;
2797e4b17023SJohn Marino
2798e4b17023SJohn Marino for (c = clauses; c ; c = OMP_CLAUSE_CHAIN (c))
2799e4b17023SJohn Marino {
2800e4b17023SJohn Marino tree val, ref, x, var;
2801e4b17023SJohn Marino bool by_ref, do_in = false, do_out = false;
2802e4b17023SJohn Marino location_t clause_loc = OMP_CLAUSE_LOCATION (c);
2803e4b17023SJohn Marino
2804e4b17023SJohn Marino switch (OMP_CLAUSE_CODE (c))
2805e4b17023SJohn Marino {
2806e4b17023SJohn Marino case OMP_CLAUSE_PRIVATE:
2807e4b17023SJohn Marino if (OMP_CLAUSE_PRIVATE_OUTER_REF (c))
2808e4b17023SJohn Marino break;
2809e4b17023SJohn Marino continue;
2810e4b17023SJohn Marino case OMP_CLAUSE_FIRSTPRIVATE:
2811e4b17023SJohn Marino case OMP_CLAUSE_COPYIN:
2812e4b17023SJohn Marino case OMP_CLAUSE_LASTPRIVATE:
2813e4b17023SJohn Marino case OMP_CLAUSE_REDUCTION:
2814e4b17023SJohn Marino break;
2815e4b17023SJohn Marino default:
2816e4b17023SJohn Marino continue;
2817e4b17023SJohn Marino }
2818e4b17023SJohn Marino
2819e4b17023SJohn Marino val = OMP_CLAUSE_DECL (c);
2820e4b17023SJohn Marino var = lookup_decl_in_outer_ctx (val, ctx);
2821e4b17023SJohn Marino
2822e4b17023SJohn Marino if (OMP_CLAUSE_CODE (c) != OMP_CLAUSE_COPYIN
2823e4b17023SJohn Marino && is_global_var (var))
2824e4b17023SJohn Marino continue;
2825e4b17023SJohn Marino if (is_variable_sized (val))
2826e4b17023SJohn Marino continue;
2827e4b17023SJohn Marino by_ref = use_pointer_for_field (val, NULL);
2828e4b17023SJohn Marino
2829e4b17023SJohn Marino switch (OMP_CLAUSE_CODE (c))
2830e4b17023SJohn Marino {
2831e4b17023SJohn Marino case OMP_CLAUSE_PRIVATE:
2832e4b17023SJohn Marino case OMP_CLAUSE_FIRSTPRIVATE:
2833e4b17023SJohn Marino case OMP_CLAUSE_COPYIN:
2834e4b17023SJohn Marino do_in = true;
2835e4b17023SJohn Marino break;
2836e4b17023SJohn Marino
2837e4b17023SJohn Marino case OMP_CLAUSE_LASTPRIVATE:
2838e4b17023SJohn Marino if (by_ref || is_reference (val))
2839e4b17023SJohn Marino {
2840e4b17023SJohn Marino if (OMP_CLAUSE_LASTPRIVATE_FIRSTPRIVATE (c))
2841e4b17023SJohn Marino continue;
2842e4b17023SJohn Marino do_in = true;
2843e4b17023SJohn Marino }
2844e4b17023SJohn Marino else
2845e4b17023SJohn Marino {
2846e4b17023SJohn Marino do_out = true;
2847e4b17023SJohn Marino if (lang_hooks.decls.omp_private_outer_ref (val))
2848e4b17023SJohn Marino do_in = true;
2849e4b17023SJohn Marino }
2850e4b17023SJohn Marino break;
2851e4b17023SJohn Marino
2852e4b17023SJohn Marino case OMP_CLAUSE_REDUCTION:
2853e4b17023SJohn Marino do_in = true;
2854e4b17023SJohn Marino do_out = !(by_ref || is_reference (val));
2855e4b17023SJohn Marino break;
2856e4b17023SJohn Marino
2857e4b17023SJohn Marino default:
2858e4b17023SJohn Marino gcc_unreachable ();
2859e4b17023SJohn Marino }
2860e4b17023SJohn Marino
2861e4b17023SJohn Marino if (do_in)
2862e4b17023SJohn Marino {
2863e4b17023SJohn Marino ref = build_sender_ref (val, ctx);
2864e4b17023SJohn Marino x = by_ref ? build_fold_addr_expr_loc (clause_loc, var) : var;
2865e4b17023SJohn Marino gimplify_assign (ref, x, ilist);
2866e4b17023SJohn Marino if (is_task_ctx (ctx))
2867e4b17023SJohn Marino DECL_ABSTRACT_ORIGIN (TREE_OPERAND (ref, 1)) = NULL;
2868e4b17023SJohn Marino }
2869e4b17023SJohn Marino
2870e4b17023SJohn Marino if (do_out)
2871e4b17023SJohn Marino {
2872e4b17023SJohn Marino ref = build_sender_ref (val, ctx);
2873e4b17023SJohn Marino gimplify_assign (var, ref, olist);
2874e4b17023SJohn Marino }
2875e4b17023SJohn Marino }
2876e4b17023SJohn Marino }
2877e4b17023SJohn Marino
2878e4b17023SJohn Marino /* Generate code to implement SHARED from the sender (aka parent)
2879e4b17023SJohn Marino side. This is trickier, since GIMPLE_OMP_PARALLEL_CLAUSES doesn't
2880e4b17023SJohn Marino list things that got automatically shared. */
2881e4b17023SJohn Marino
2882e4b17023SJohn Marino static void
lower_send_shared_vars(gimple_seq * ilist,gimple_seq * olist,omp_context * ctx)2883e4b17023SJohn Marino lower_send_shared_vars (gimple_seq *ilist, gimple_seq *olist, omp_context *ctx)
2884e4b17023SJohn Marino {
2885e4b17023SJohn Marino tree var, ovar, nvar, f, x, record_type;
2886e4b17023SJohn Marino
2887e4b17023SJohn Marino if (ctx->record_type == NULL)
2888e4b17023SJohn Marino return;
2889e4b17023SJohn Marino
2890e4b17023SJohn Marino record_type = ctx->srecord_type ? ctx->srecord_type : ctx->record_type;
2891e4b17023SJohn Marino for (f = TYPE_FIELDS (record_type); f ; f = DECL_CHAIN (f))
2892e4b17023SJohn Marino {
2893e4b17023SJohn Marino ovar = DECL_ABSTRACT_ORIGIN (f);
2894e4b17023SJohn Marino nvar = maybe_lookup_decl (ovar, ctx);
2895e4b17023SJohn Marino if (!nvar || !DECL_HAS_VALUE_EXPR_P (nvar))
2896e4b17023SJohn Marino continue;
2897e4b17023SJohn Marino
2898e4b17023SJohn Marino /* If CTX is a nested parallel directive. Find the immediately
2899e4b17023SJohn Marino enclosing parallel or workshare construct that contains a
2900e4b17023SJohn Marino mapping for OVAR. */
2901e4b17023SJohn Marino var = lookup_decl_in_outer_ctx (ovar, ctx);
2902e4b17023SJohn Marino
2903e4b17023SJohn Marino if (use_pointer_for_field (ovar, ctx))
2904e4b17023SJohn Marino {
2905e4b17023SJohn Marino x = build_sender_ref (ovar, ctx);
2906e4b17023SJohn Marino var = build_fold_addr_expr (var);
2907e4b17023SJohn Marino gimplify_assign (x, var, ilist);
2908e4b17023SJohn Marino }
2909e4b17023SJohn Marino else
2910e4b17023SJohn Marino {
2911e4b17023SJohn Marino x = build_sender_ref (ovar, ctx);
2912e4b17023SJohn Marino gimplify_assign (x, var, ilist);
2913e4b17023SJohn Marino
2914e4b17023SJohn Marino if (!TREE_READONLY (var)
2915e4b17023SJohn Marino /* We don't need to receive a new reference to a result
2916e4b17023SJohn Marino or parm decl. In fact we may not store to it as we will
2917e4b17023SJohn Marino invalidate any pending RSO and generate wrong gimple
2918e4b17023SJohn Marino during inlining. */
2919e4b17023SJohn Marino && !((TREE_CODE (var) == RESULT_DECL
2920e4b17023SJohn Marino || TREE_CODE (var) == PARM_DECL)
2921e4b17023SJohn Marino && DECL_BY_REFERENCE (var)))
2922e4b17023SJohn Marino {
2923e4b17023SJohn Marino x = build_sender_ref (ovar, ctx);
2924e4b17023SJohn Marino gimplify_assign (var, x, olist);
2925e4b17023SJohn Marino }
2926e4b17023SJohn Marino }
2927e4b17023SJohn Marino }
2928e4b17023SJohn Marino }
2929e4b17023SJohn Marino
2930e4b17023SJohn Marino
2931e4b17023SJohn Marino /* A convenience function to build an empty GIMPLE_COND with just the
2932e4b17023SJohn Marino condition. */
2933e4b17023SJohn Marino
2934e4b17023SJohn Marino static gimple
gimple_build_cond_empty(tree cond)2935e4b17023SJohn Marino gimple_build_cond_empty (tree cond)
2936e4b17023SJohn Marino {
2937e4b17023SJohn Marino enum tree_code pred_code;
2938e4b17023SJohn Marino tree lhs, rhs;
2939e4b17023SJohn Marino
2940e4b17023SJohn Marino gimple_cond_get_ops_from_tree (cond, &pred_code, &lhs, &rhs);
2941e4b17023SJohn Marino return gimple_build_cond (pred_code, lhs, rhs, NULL_TREE, NULL_TREE);
2942e4b17023SJohn Marino }
2943e4b17023SJohn Marino
2944e4b17023SJohn Marino
2945e4b17023SJohn Marino /* Build the function calls to GOMP_parallel_start etc to actually
2946e4b17023SJohn Marino generate the parallel operation. REGION is the parallel region
2947e4b17023SJohn Marino being expanded. BB is the block where to insert the code. WS_ARGS
2948e4b17023SJohn Marino will be set if this is a call to a combined parallel+workshare
2949e4b17023SJohn Marino construct, it contains the list of additional arguments needed by
2950e4b17023SJohn Marino the workshare construct. */
2951e4b17023SJohn Marino
2952e4b17023SJohn Marino static void
expand_parallel_call(struct omp_region * region,basic_block bb,gimple entry_stmt,VEC (tree,gc)* ws_args)2953e4b17023SJohn Marino expand_parallel_call (struct omp_region *region, basic_block bb,
2954e4b17023SJohn Marino gimple entry_stmt, VEC(tree,gc) *ws_args)
2955e4b17023SJohn Marino {
2956e4b17023SJohn Marino tree t, t1, t2, val, cond, c, clauses;
2957e4b17023SJohn Marino gimple_stmt_iterator gsi;
2958e4b17023SJohn Marino gimple stmt;
2959e4b17023SJohn Marino enum built_in_function start_ix;
2960e4b17023SJohn Marino int start_ix2;
2961e4b17023SJohn Marino location_t clause_loc;
2962e4b17023SJohn Marino VEC(tree,gc) *args;
2963e4b17023SJohn Marino
2964e4b17023SJohn Marino clauses = gimple_omp_parallel_clauses (entry_stmt);
2965e4b17023SJohn Marino
2966e4b17023SJohn Marino /* Determine what flavor of GOMP_parallel_start we will be
2967e4b17023SJohn Marino emitting. */
2968e4b17023SJohn Marino start_ix = BUILT_IN_GOMP_PARALLEL_START;
2969e4b17023SJohn Marino if (is_combined_parallel (region))
2970e4b17023SJohn Marino {
2971e4b17023SJohn Marino switch (region->inner->type)
2972e4b17023SJohn Marino {
2973e4b17023SJohn Marino case GIMPLE_OMP_FOR:
2974e4b17023SJohn Marino gcc_assert (region->inner->sched_kind != OMP_CLAUSE_SCHEDULE_AUTO);
2975e4b17023SJohn Marino start_ix2 = ((int)BUILT_IN_GOMP_PARALLEL_LOOP_STATIC_START
2976e4b17023SJohn Marino + (region->inner->sched_kind
2977e4b17023SJohn Marino == OMP_CLAUSE_SCHEDULE_RUNTIME
2978e4b17023SJohn Marino ? 3 : region->inner->sched_kind));
2979e4b17023SJohn Marino start_ix = (enum built_in_function)start_ix2;
2980e4b17023SJohn Marino break;
2981e4b17023SJohn Marino case GIMPLE_OMP_SECTIONS:
2982e4b17023SJohn Marino start_ix = BUILT_IN_GOMP_PARALLEL_SECTIONS_START;
2983e4b17023SJohn Marino break;
2984e4b17023SJohn Marino default:
2985e4b17023SJohn Marino gcc_unreachable ();
2986e4b17023SJohn Marino }
2987e4b17023SJohn Marino }
2988e4b17023SJohn Marino
2989e4b17023SJohn Marino /* By default, the value of NUM_THREADS is zero (selected at run time)
2990e4b17023SJohn Marino and there is no conditional. */
2991e4b17023SJohn Marino cond = NULL_TREE;
2992e4b17023SJohn Marino val = build_int_cst (unsigned_type_node, 0);
2993e4b17023SJohn Marino
2994e4b17023SJohn Marino c = find_omp_clause (clauses, OMP_CLAUSE_IF);
2995e4b17023SJohn Marino if (c)
2996e4b17023SJohn Marino cond = OMP_CLAUSE_IF_EXPR (c);
2997e4b17023SJohn Marino
2998e4b17023SJohn Marino c = find_omp_clause (clauses, OMP_CLAUSE_NUM_THREADS);
2999e4b17023SJohn Marino if (c)
3000e4b17023SJohn Marino {
3001e4b17023SJohn Marino val = OMP_CLAUSE_NUM_THREADS_EXPR (c);
3002e4b17023SJohn Marino clause_loc = OMP_CLAUSE_LOCATION (c);
3003e4b17023SJohn Marino }
3004e4b17023SJohn Marino else
3005e4b17023SJohn Marino clause_loc = gimple_location (entry_stmt);
3006e4b17023SJohn Marino
3007e4b17023SJohn Marino /* Ensure 'val' is of the correct type. */
3008e4b17023SJohn Marino val = fold_convert_loc (clause_loc, unsigned_type_node, val);
3009e4b17023SJohn Marino
3010e4b17023SJohn Marino /* If we found the clause 'if (cond)', build either
3011e4b17023SJohn Marino (cond != 0) or (cond ? val : 1u). */
3012e4b17023SJohn Marino if (cond)
3013e4b17023SJohn Marino {
3014e4b17023SJohn Marino gimple_stmt_iterator gsi;
3015e4b17023SJohn Marino
3016e4b17023SJohn Marino cond = gimple_boolify (cond);
3017e4b17023SJohn Marino
3018e4b17023SJohn Marino if (integer_zerop (val))
3019e4b17023SJohn Marino val = fold_build2_loc (clause_loc,
3020e4b17023SJohn Marino EQ_EXPR, unsigned_type_node, cond,
3021e4b17023SJohn Marino build_int_cst (TREE_TYPE (cond), 0));
3022e4b17023SJohn Marino else
3023e4b17023SJohn Marino {
3024e4b17023SJohn Marino basic_block cond_bb, then_bb, else_bb;
3025e4b17023SJohn Marino edge e, e_then, e_else;
3026e4b17023SJohn Marino tree tmp_then, tmp_else, tmp_join, tmp_var;
3027e4b17023SJohn Marino
3028e4b17023SJohn Marino tmp_var = create_tmp_var (TREE_TYPE (val), NULL);
3029e4b17023SJohn Marino if (gimple_in_ssa_p (cfun))
3030e4b17023SJohn Marino {
3031e4b17023SJohn Marino tmp_then = make_ssa_name (tmp_var, NULL);
3032e4b17023SJohn Marino tmp_else = make_ssa_name (tmp_var, NULL);
3033e4b17023SJohn Marino tmp_join = make_ssa_name (tmp_var, NULL);
3034e4b17023SJohn Marino }
3035e4b17023SJohn Marino else
3036e4b17023SJohn Marino {
3037e4b17023SJohn Marino tmp_then = tmp_var;
3038e4b17023SJohn Marino tmp_else = tmp_var;
3039e4b17023SJohn Marino tmp_join = tmp_var;
3040e4b17023SJohn Marino }
3041e4b17023SJohn Marino
3042e4b17023SJohn Marino e = split_block (bb, NULL);
3043e4b17023SJohn Marino cond_bb = e->src;
3044e4b17023SJohn Marino bb = e->dest;
3045e4b17023SJohn Marino remove_edge (e);
3046e4b17023SJohn Marino
3047e4b17023SJohn Marino then_bb = create_empty_bb (cond_bb);
3048e4b17023SJohn Marino else_bb = create_empty_bb (then_bb);
3049e4b17023SJohn Marino set_immediate_dominator (CDI_DOMINATORS, then_bb, cond_bb);
3050e4b17023SJohn Marino set_immediate_dominator (CDI_DOMINATORS, else_bb, cond_bb);
3051e4b17023SJohn Marino
3052e4b17023SJohn Marino stmt = gimple_build_cond_empty (cond);
3053e4b17023SJohn Marino gsi = gsi_start_bb (cond_bb);
3054e4b17023SJohn Marino gsi_insert_after (&gsi, stmt, GSI_CONTINUE_LINKING);
3055e4b17023SJohn Marino
3056e4b17023SJohn Marino gsi = gsi_start_bb (then_bb);
3057e4b17023SJohn Marino stmt = gimple_build_assign (tmp_then, val);
3058e4b17023SJohn Marino gsi_insert_after (&gsi, stmt, GSI_CONTINUE_LINKING);
3059e4b17023SJohn Marino
3060e4b17023SJohn Marino gsi = gsi_start_bb (else_bb);
3061e4b17023SJohn Marino stmt = gimple_build_assign
3062e4b17023SJohn Marino (tmp_else, build_int_cst (unsigned_type_node, 1));
3063e4b17023SJohn Marino gsi_insert_after (&gsi, stmt, GSI_CONTINUE_LINKING);
3064e4b17023SJohn Marino
3065e4b17023SJohn Marino make_edge (cond_bb, then_bb, EDGE_TRUE_VALUE);
3066e4b17023SJohn Marino make_edge (cond_bb, else_bb, EDGE_FALSE_VALUE);
3067e4b17023SJohn Marino e_then = make_edge (then_bb, bb, EDGE_FALLTHRU);
3068e4b17023SJohn Marino e_else = make_edge (else_bb, bb, EDGE_FALLTHRU);
3069e4b17023SJohn Marino
3070e4b17023SJohn Marino if (gimple_in_ssa_p (cfun))
3071e4b17023SJohn Marino {
3072e4b17023SJohn Marino gimple phi = create_phi_node (tmp_join, bb);
3073e4b17023SJohn Marino SSA_NAME_DEF_STMT (tmp_join) = phi;
3074e4b17023SJohn Marino add_phi_arg (phi, tmp_then, e_then, UNKNOWN_LOCATION);
3075e4b17023SJohn Marino add_phi_arg (phi, tmp_else, e_else, UNKNOWN_LOCATION);
3076e4b17023SJohn Marino }
3077e4b17023SJohn Marino
3078e4b17023SJohn Marino val = tmp_join;
3079e4b17023SJohn Marino }
3080e4b17023SJohn Marino
3081e4b17023SJohn Marino gsi = gsi_start_bb (bb);
3082e4b17023SJohn Marino val = force_gimple_operand_gsi (&gsi, val, true, NULL_TREE,
3083e4b17023SJohn Marino false, GSI_CONTINUE_LINKING);
3084e4b17023SJohn Marino }
3085e4b17023SJohn Marino
3086e4b17023SJohn Marino gsi = gsi_last_bb (bb);
3087e4b17023SJohn Marino t = gimple_omp_parallel_data_arg (entry_stmt);
3088e4b17023SJohn Marino if (t == NULL)
3089e4b17023SJohn Marino t1 = null_pointer_node;
3090e4b17023SJohn Marino else
3091e4b17023SJohn Marino t1 = build_fold_addr_expr (t);
3092e4b17023SJohn Marino t2 = build_fold_addr_expr (gimple_omp_parallel_child_fn (entry_stmt));
3093e4b17023SJohn Marino
3094e4b17023SJohn Marino args = VEC_alloc (tree, gc, 3 + VEC_length (tree, ws_args));
3095e4b17023SJohn Marino VEC_quick_push (tree, args, t2);
3096e4b17023SJohn Marino VEC_quick_push (tree, args, t1);
3097e4b17023SJohn Marino VEC_quick_push (tree, args, val);
3098e4b17023SJohn Marino VEC_splice (tree, args, ws_args);
3099e4b17023SJohn Marino
3100e4b17023SJohn Marino t = build_call_expr_loc_vec (UNKNOWN_LOCATION,
3101e4b17023SJohn Marino builtin_decl_explicit (start_ix), args);
3102e4b17023SJohn Marino
3103e4b17023SJohn Marino force_gimple_operand_gsi (&gsi, t, true, NULL_TREE,
3104e4b17023SJohn Marino false, GSI_CONTINUE_LINKING);
3105e4b17023SJohn Marino
3106e4b17023SJohn Marino t = gimple_omp_parallel_data_arg (entry_stmt);
3107e4b17023SJohn Marino if (t == NULL)
3108e4b17023SJohn Marino t = null_pointer_node;
3109e4b17023SJohn Marino else
3110e4b17023SJohn Marino t = build_fold_addr_expr (t);
3111e4b17023SJohn Marino t = build_call_expr_loc (gimple_location (entry_stmt),
3112e4b17023SJohn Marino gimple_omp_parallel_child_fn (entry_stmt), 1, t);
3113e4b17023SJohn Marino force_gimple_operand_gsi (&gsi, t, true, NULL_TREE,
3114e4b17023SJohn Marino false, GSI_CONTINUE_LINKING);
3115e4b17023SJohn Marino
3116e4b17023SJohn Marino t = build_call_expr_loc (gimple_location (entry_stmt),
3117e4b17023SJohn Marino builtin_decl_explicit (BUILT_IN_GOMP_PARALLEL_END),
3118e4b17023SJohn Marino 0);
3119e4b17023SJohn Marino force_gimple_operand_gsi (&gsi, t, true, NULL_TREE,
3120e4b17023SJohn Marino false, GSI_CONTINUE_LINKING);
3121e4b17023SJohn Marino }
3122e4b17023SJohn Marino
3123e4b17023SJohn Marino
3124e4b17023SJohn Marino /* Build the function call to GOMP_task to actually
3125e4b17023SJohn Marino generate the task operation. BB is the block where to insert the code. */
3126e4b17023SJohn Marino
3127e4b17023SJohn Marino static void
expand_task_call(basic_block bb,gimple entry_stmt)3128e4b17023SJohn Marino expand_task_call (basic_block bb, gimple entry_stmt)
3129e4b17023SJohn Marino {
3130e4b17023SJohn Marino tree t, t1, t2, t3, flags, cond, c, c2, clauses;
3131e4b17023SJohn Marino gimple_stmt_iterator gsi;
3132e4b17023SJohn Marino location_t loc = gimple_location (entry_stmt);
3133e4b17023SJohn Marino
3134e4b17023SJohn Marino clauses = gimple_omp_task_clauses (entry_stmt);
3135e4b17023SJohn Marino
3136e4b17023SJohn Marino c = find_omp_clause (clauses, OMP_CLAUSE_IF);
3137e4b17023SJohn Marino if (c)
3138e4b17023SJohn Marino cond = gimple_boolify (OMP_CLAUSE_IF_EXPR (c));
3139e4b17023SJohn Marino else
3140e4b17023SJohn Marino cond = boolean_true_node;
3141e4b17023SJohn Marino
3142e4b17023SJohn Marino c = find_omp_clause (clauses, OMP_CLAUSE_UNTIED);
3143e4b17023SJohn Marino c2 = find_omp_clause (clauses, OMP_CLAUSE_MERGEABLE);
3144e4b17023SJohn Marino flags = build_int_cst (unsigned_type_node,
3145e4b17023SJohn Marino (c ? 1 : 0) + (c2 ? 4 : 0));
3146e4b17023SJohn Marino
3147e4b17023SJohn Marino c = find_omp_clause (clauses, OMP_CLAUSE_FINAL);
3148e4b17023SJohn Marino if (c)
3149e4b17023SJohn Marino {
3150e4b17023SJohn Marino c = gimple_boolify (OMP_CLAUSE_FINAL_EXPR (c));
3151e4b17023SJohn Marino c = fold_build3_loc (loc, COND_EXPR, unsigned_type_node, c,
3152e4b17023SJohn Marino build_int_cst (unsigned_type_node, 2),
3153e4b17023SJohn Marino build_int_cst (unsigned_type_node, 0));
3154e4b17023SJohn Marino flags = fold_build2_loc (loc, PLUS_EXPR, unsigned_type_node, flags, c);
3155e4b17023SJohn Marino }
3156e4b17023SJohn Marino
3157e4b17023SJohn Marino gsi = gsi_last_bb (bb);
3158e4b17023SJohn Marino t = gimple_omp_task_data_arg (entry_stmt);
3159e4b17023SJohn Marino if (t == NULL)
3160e4b17023SJohn Marino t2 = null_pointer_node;
3161e4b17023SJohn Marino else
3162e4b17023SJohn Marino t2 = build_fold_addr_expr_loc (loc, t);
3163e4b17023SJohn Marino t1 = build_fold_addr_expr_loc (loc, gimple_omp_task_child_fn (entry_stmt));
3164e4b17023SJohn Marino t = gimple_omp_task_copy_fn (entry_stmt);
3165e4b17023SJohn Marino if (t == NULL)
3166e4b17023SJohn Marino t3 = null_pointer_node;
3167e4b17023SJohn Marino else
3168e4b17023SJohn Marino t3 = build_fold_addr_expr_loc (loc, t);
3169e4b17023SJohn Marino
3170e4b17023SJohn Marino t = build_call_expr (builtin_decl_explicit (BUILT_IN_GOMP_TASK),
3171e4b17023SJohn Marino 7, t1, t2, t3,
3172e4b17023SJohn Marino gimple_omp_task_arg_size (entry_stmt),
3173e4b17023SJohn Marino gimple_omp_task_arg_align (entry_stmt), cond, flags);
3174e4b17023SJohn Marino
3175e4b17023SJohn Marino force_gimple_operand_gsi (&gsi, t, true, NULL_TREE,
3176e4b17023SJohn Marino false, GSI_CONTINUE_LINKING);
3177e4b17023SJohn Marino }
3178e4b17023SJohn Marino
3179e4b17023SJohn Marino
3180e4b17023SJohn Marino /* If exceptions are enabled, wrap the statements in BODY in a MUST_NOT_THROW
3181e4b17023SJohn Marino catch handler and return it. This prevents programs from violating the
3182e4b17023SJohn Marino structured block semantics with throws. */
3183e4b17023SJohn Marino
3184e4b17023SJohn Marino static gimple_seq
maybe_catch_exception(gimple_seq body)3185e4b17023SJohn Marino maybe_catch_exception (gimple_seq body)
3186e4b17023SJohn Marino {
3187e4b17023SJohn Marino gimple g;
3188e4b17023SJohn Marino tree decl;
3189e4b17023SJohn Marino
3190e4b17023SJohn Marino if (!flag_exceptions)
3191e4b17023SJohn Marino return body;
3192e4b17023SJohn Marino
3193e4b17023SJohn Marino if (lang_hooks.eh_protect_cleanup_actions != NULL)
3194e4b17023SJohn Marino decl = lang_hooks.eh_protect_cleanup_actions ();
3195e4b17023SJohn Marino else
3196e4b17023SJohn Marino decl = builtin_decl_explicit (BUILT_IN_TRAP);
3197e4b17023SJohn Marino
3198e4b17023SJohn Marino g = gimple_build_eh_must_not_throw (decl);
3199e4b17023SJohn Marino g = gimple_build_try (body, gimple_seq_alloc_with_stmt (g),
3200e4b17023SJohn Marino GIMPLE_TRY_CATCH);
3201e4b17023SJohn Marino
3202e4b17023SJohn Marino return gimple_seq_alloc_with_stmt (g);
3203e4b17023SJohn Marino }
3204e4b17023SJohn Marino
3205e4b17023SJohn Marino /* Chain all the DECLs in LIST by their TREE_CHAIN fields. */
3206e4b17023SJohn Marino
3207e4b17023SJohn Marino static tree
vec2chain(VEC (tree,gc)* v)3208e4b17023SJohn Marino vec2chain (VEC(tree,gc) *v)
3209e4b17023SJohn Marino {
3210e4b17023SJohn Marino tree chain = NULL_TREE, t;
3211e4b17023SJohn Marino unsigned ix;
3212e4b17023SJohn Marino
3213e4b17023SJohn Marino FOR_EACH_VEC_ELT_REVERSE (tree, v, ix, t)
3214e4b17023SJohn Marino {
3215e4b17023SJohn Marino DECL_CHAIN (t) = chain;
3216e4b17023SJohn Marino chain = t;
3217e4b17023SJohn Marino }
3218e4b17023SJohn Marino
3219e4b17023SJohn Marino return chain;
3220e4b17023SJohn Marino }
3221e4b17023SJohn Marino
3222e4b17023SJohn Marino
3223e4b17023SJohn Marino /* Remove barriers in REGION->EXIT's block. Note that this is only
3224e4b17023SJohn Marino valid for GIMPLE_OMP_PARALLEL regions. Since the end of a parallel region
3225e4b17023SJohn Marino is an implicit barrier, any workshare inside the GIMPLE_OMP_PARALLEL that
3226e4b17023SJohn Marino left a barrier at the end of the GIMPLE_OMP_PARALLEL region can now be
3227e4b17023SJohn Marino removed. */
3228e4b17023SJohn Marino
3229e4b17023SJohn Marino static void
remove_exit_barrier(struct omp_region * region)3230e4b17023SJohn Marino remove_exit_barrier (struct omp_region *region)
3231e4b17023SJohn Marino {
3232e4b17023SJohn Marino gimple_stmt_iterator gsi;
3233e4b17023SJohn Marino basic_block exit_bb;
3234e4b17023SJohn Marino edge_iterator ei;
3235e4b17023SJohn Marino edge e;
3236e4b17023SJohn Marino gimple stmt;
3237e4b17023SJohn Marino int any_addressable_vars = -1;
3238e4b17023SJohn Marino
3239e4b17023SJohn Marino exit_bb = region->exit;
3240e4b17023SJohn Marino
3241e4b17023SJohn Marino /* If the parallel region doesn't return, we don't have REGION->EXIT
3242e4b17023SJohn Marino block at all. */
3243e4b17023SJohn Marino if (! exit_bb)
3244e4b17023SJohn Marino return;
3245e4b17023SJohn Marino
3246e4b17023SJohn Marino /* The last insn in the block will be the parallel's GIMPLE_OMP_RETURN. The
3247e4b17023SJohn Marino workshare's GIMPLE_OMP_RETURN will be in a preceding block. The kinds of
3248e4b17023SJohn Marino statements that can appear in between are extremely limited -- no
3249e4b17023SJohn Marino memory operations at all. Here, we allow nothing at all, so the
3250e4b17023SJohn Marino only thing we allow to precede this GIMPLE_OMP_RETURN is a label. */
3251e4b17023SJohn Marino gsi = gsi_last_bb (exit_bb);
3252e4b17023SJohn Marino gcc_assert (gimple_code (gsi_stmt (gsi)) == GIMPLE_OMP_RETURN);
3253e4b17023SJohn Marino gsi_prev (&gsi);
3254e4b17023SJohn Marino if (!gsi_end_p (gsi) && gimple_code (gsi_stmt (gsi)) != GIMPLE_LABEL)
3255e4b17023SJohn Marino return;
3256e4b17023SJohn Marino
3257e4b17023SJohn Marino FOR_EACH_EDGE (e, ei, exit_bb->preds)
3258e4b17023SJohn Marino {
3259e4b17023SJohn Marino gsi = gsi_last_bb (e->src);
3260e4b17023SJohn Marino if (gsi_end_p (gsi))
3261e4b17023SJohn Marino continue;
3262e4b17023SJohn Marino stmt = gsi_stmt (gsi);
3263e4b17023SJohn Marino if (gimple_code (stmt) == GIMPLE_OMP_RETURN
3264e4b17023SJohn Marino && !gimple_omp_return_nowait_p (stmt))
3265e4b17023SJohn Marino {
3266e4b17023SJohn Marino /* OpenMP 3.0 tasks unfortunately prevent this optimization
3267e4b17023SJohn Marino in many cases. If there could be tasks queued, the barrier
3268e4b17023SJohn Marino might be needed to let the tasks run before some local
3269e4b17023SJohn Marino variable of the parallel that the task uses as shared
3270e4b17023SJohn Marino runs out of scope. The task can be spawned either
3271e4b17023SJohn Marino from within current function (this would be easy to check)
3272e4b17023SJohn Marino or from some function it calls and gets passed an address
3273e4b17023SJohn Marino of such a variable. */
3274e4b17023SJohn Marino if (any_addressable_vars < 0)
3275e4b17023SJohn Marino {
3276e4b17023SJohn Marino gimple parallel_stmt = last_stmt (region->entry);
3277e4b17023SJohn Marino tree child_fun = gimple_omp_parallel_child_fn (parallel_stmt);
3278e4b17023SJohn Marino tree local_decls, block, decl;
3279e4b17023SJohn Marino unsigned ix;
3280e4b17023SJohn Marino
3281e4b17023SJohn Marino any_addressable_vars = 0;
3282e4b17023SJohn Marino FOR_EACH_LOCAL_DECL (DECL_STRUCT_FUNCTION (child_fun), ix, decl)
3283e4b17023SJohn Marino if (TREE_ADDRESSABLE (decl))
3284e4b17023SJohn Marino {
3285e4b17023SJohn Marino any_addressable_vars = 1;
3286e4b17023SJohn Marino break;
3287e4b17023SJohn Marino }
3288e4b17023SJohn Marino for (block = gimple_block (stmt);
3289e4b17023SJohn Marino !any_addressable_vars
3290e4b17023SJohn Marino && block
3291e4b17023SJohn Marino && TREE_CODE (block) == BLOCK;
3292e4b17023SJohn Marino block = BLOCK_SUPERCONTEXT (block))
3293e4b17023SJohn Marino {
3294e4b17023SJohn Marino for (local_decls = BLOCK_VARS (block);
3295e4b17023SJohn Marino local_decls;
3296e4b17023SJohn Marino local_decls = DECL_CHAIN (local_decls))
3297e4b17023SJohn Marino if (TREE_ADDRESSABLE (local_decls))
3298e4b17023SJohn Marino {
3299e4b17023SJohn Marino any_addressable_vars = 1;
3300e4b17023SJohn Marino break;
3301e4b17023SJohn Marino }
3302e4b17023SJohn Marino if (block == gimple_block (parallel_stmt))
3303e4b17023SJohn Marino break;
3304e4b17023SJohn Marino }
3305e4b17023SJohn Marino }
3306e4b17023SJohn Marino if (!any_addressable_vars)
3307e4b17023SJohn Marino gimple_omp_return_set_nowait (stmt);
3308e4b17023SJohn Marino }
3309e4b17023SJohn Marino }
3310e4b17023SJohn Marino }
3311e4b17023SJohn Marino
3312e4b17023SJohn Marino static void
remove_exit_barriers(struct omp_region * region)3313e4b17023SJohn Marino remove_exit_barriers (struct omp_region *region)
3314e4b17023SJohn Marino {
3315e4b17023SJohn Marino if (region->type == GIMPLE_OMP_PARALLEL)
3316e4b17023SJohn Marino remove_exit_barrier (region);
3317e4b17023SJohn Marino
3318e4b17023SJohn Marino if (region->inner)
3319e4b17023SJohn Marino {
3320e4b17023SJohn Marino region = region->inner;
3321e4b17023SJohn Marino remove_exit_barriers (region);
3322e4b17023SJohn Marino while (region->next)
3323e4b17023SJohn Marino {
3324e4b17023SJohn Marino region = region->next;
3325e4b17023SJohn Marino remove_exit_barriers (region);
3326e4b17023SJohn Marino }
3327e4b17023SJohn Marino }
3328e4b17023SJohn Marino }
3329e4b17023SJohn Marino
3330e4b17023SJohn Marino /* Optimize omp_get_thread_num () and omp_get_num_threads ()
3331e4b17023SJohn Marino calls. These can't be declared as const functions, but
3332e4b17023SJohn Marino within one parallel body they are constant, so they can be
3333e4b17023SJohn Marino transformed there into __builtin_omp_get_{thread_num,num_threads} ()
3334e4b17023SJohn Marino which are declared const. Similarly for task body, except
3335e4b17023SJohn Marino that in untied task omp_get_thread_num () can change at any task
3336e4b17023SJohn Marino scheduling point. */
3337e4b17023SJohn Marino
3338e4b17023SJohn Marino static void
optimize_omp_library_calls(gimple entry_stmt)3339e4b17023SJohn Marino optimize_omp_library_calls (gimple entry_stmt)
3340e4b17023SJohn Marino {
3341e4b17023SJohn Marino basic_block bb;
3342e4b17023SJohn Marino gimple_stmt_iterator gsi;
3343e4b17023SJohn Marino tree thr_num_tree = builtin_decl_explicit (BUILT_IN_OMP_GET_THREAD_NUM);
3344e4b17023SJohn Marino tree thr_num_id = DECL_ASSEMBLER_NAME (thr_num_tree);
3345e4b17023SJohn Marino tree num_thr_tree = builtin_decl_explicit (BUILT_IN_OMP_GET_NUM_THREADS);
3346e4b17023SJohn Marino tree num_thr_id = DECL_ASSEMBLER_NAME (num_thr_tree);
3347e4b17023SJohn Marino bool untied_task = (gimple_code (entry_stmt) == GIMPLE_OMP_TASK
3348e4b17023SJohn Marino && find_omp_clause (gimple_omp_task_clauses (entry_stmt),
3349e4b17023SJohn Marino OMP_CLAUSE_UNTIED) != NULL);
3350e4b17023SJohn Marino
3351e4b17023SJohn Marino FOR_EACH_BB (bb)
3352e4b17023SJohn Marino for (gsi = gsi_start_bb (bb); !gsi_end_p (gsi); gsi_next (&gsi))
3353e4b17023SJohn Marino {
3354e4b17023SJohn Marino gimple call = gsi_stmt (gsi);
3355e4b17023SJohn Marino tree decl;
3356e4b17023SJohn Marino
3357e4b17023SJohn Marino if (is_gimple_call (call)
3358e4b17023SJohn Marino && (decl = gimple_call_fndecl (call))
3359e4b17023SJohn Marino && DECL_EXTERNAL (decl)
3360e4b17023SJohn Marino && TREE_PUBLIC (decl)
3361e4b17023SJohn Marino && DECL_INITIAL (decl) == NULL)
3362e4b17023SJohn Marino {
3363e4b17023SJohn Marino tree built_in;
3364e4b17023SJohn Marino
3365e4b17023SJohn Marino if (DECL_NAME (decl) == thr_num_id)
3366e4b17023SJohn Marino {
3367e4b17023SJohn Marino /* In #pragma omp task untied omp_get_thread_num () can change
3368e4b17023SJohn Marino during the execution of the task region. */
3369e4b17023SJohn Marino if (untied_task)
3370e4b17023SJohn Marino continue;
3371e4b17023SJohn Marino built_in = builtin_decl_explicit (BUILT_IN_OMP_GET_THREAD_NUM);
3372e4b17023SJohn Marino }
3373e4b17023SJohn Marino else if (DECL_NAME (decl) == num_thr_id)
3374e4b17023SJohn Marino built_in = builtin_decl_explicit (BUILT_IN_OMP_GET_NUM_THREADS);
3375e4b17023SJohn Marino else
3376e4b17023SJohn Marino continue;
3377e4b17023SJohn Marino
3378e4b17023SJohn Marino if (DECL_ASSEMBLER_NAME (decl) != DECL_ASSEMBLER_NAME (built_in)
3379e4b17023SJohn Marino || gimple_call_num_args (call) != 0)
3380e4b17023SJohn Marino continue;
3381e4b17023SJohn Marino
3382e4b17023SJohn Marino if (flag_exceptions && !TREE_NOTHROW (decl))
3383e4b17023SJohn Marino continue;
3384e4b17023SJohn Marino
3385e4b17023SJohn Marino if (TREE_CODE (TREE_TYPE (decl)) != FUNCTION_TYPE
3386e4b17023SJohn Marino || !types_compatible_p (TREE_TYPE (TREE_TYPE (decl)),
3387e4b17023SJohn Marino TREE_TYPE (TREE_TYPE (built_in))))
3388e4b17023SJohn Marino continue;
3389e4b17023SJohn Marino
3390e4b17023SJohn Marino gimple_call_set_fndecl (call, built_in);
3391e4b17023SJohn Marino }
3392e4b17023SJohn Marino }
3393e4b17023SJohn Marino }
3394e4b17023SJohn Marino
3395e4b17023SJohn Marino /* Expand the OpenMP parallel or task directive starting at REGION. */
3396e4b17023SJohn Marino
3397e4b17023SJohn Marino static void
expand_omp_taskreg(struct omp_region * region)3398e4b17023SJohn Marino expand_omp_taskreg (struct omp_region *region)
3399e4b17023SJohn Marino {
3400e4b17023SJohn Marino basic_block entry_bb, exit_bb, new_bb;
3401e4b17023SJohn Marino struct function *child_cfun;
3402e4b17023SJohn Marino tree child_fn, block, t;
3403e4b17023SJohn Marino tree save_current;
3404e4b17023SJohn Marino gimple_stmt_iterator gsi;
3405e4b17023SJohn Marino gimple entry_stmt, stmt;
3406e4b17023SJohn Marino edge e;
3407e4b17023SJohn Marino VEC(tree,gc) *ws_args;
3408e4b17023SJohn Marino
3409e4b17023SJohn Marino entry_stmt = last_stmt (region->entry);
3410e4b17023SJohn Marino child_fn = gimple_omp_taskreg_child_fn (entry_stmt);
3411e4b17023SJohn Marino child_cfun = DECL_STRUCT_FUNCTION (child_fn);
3412e4b17023SJohn Marino /* If this function has been already instrumented, make sure
3413e4b17023SJohn Marino the child function isn't instrumented again. */
3414e4b17023SJohn Marino child_cfun->after_tree_profile = cfun->after_tree_profile;
3415e4b17023SJohn Marino
3416e4b17023SJohn Marino entry_bb = region->entry;
3417e4b17023SJohn Marino exit_bb = region->exit;
3418e4b17023SJohn Marino
3419e4b17023SJohn Marino if (is_combined_parallel (region))
3420e4b17023SJohn Marino ws_args = region->ws_args;
3421e4b17023SJohn Marino else
3422e4b17023SJohn Marino ws_args = NULL;
3423e4b17023SJohn Marino
3424e4b17023SJohn Marino if (child_cfun->cfg)
3425e4b17023SJohn Marino {
3426e4b17023SJohn Marino /* Due to inlining, it may happen that we have already outlined
3427e4b17023SJohn Marino the region, in which case all we need to do is make the
3428e4b17023SJohn Marino sub-graph unreachable and emit the parallel call. */
3429e4b17023SJohn Marino edge entry_succ_e, exit_succ_e;
3430e4b17023SJohn Marino gimple_stmt_iterator gsi;
3431e4b17023SJohn Marino
3432e4b17023SJohn Marino entry_succ_e = single_succ_edge (entry_bb);
3433e4b17023SJohn Marino
3434e4b17023SJohn Marino gsi = gsi_last_bb (entry_bb);
3435e4b17023SJohn Marino gcc_assert (gimple_code (gsi_stmt (gsi)) == GIMPLE_OMP_PARALLEL
3436e4b17023SJohn Marino || gimple_code (gsi_stmt (gsi)) == GIMPLE_OMP_TASK);
3437e4b17023SJohn Marino gsi_remove (&gsi, true);
3438e4b17023SJohn Marino
3439e4b17023SJohn Marino new_bb = entry_bb;
3440e4b17023SJohn Marino if (exit_bb)
3441e4b17023SJohn Marino {
3442e4b17023SJohn Marino exit_succ_e = single_succ_edge (exit_bb);
3443e4b17023SJohn Marino make_edge (new_bb, exit_succ_e->dest, EDGE_FALLTHRU);
3444e4b17023SJohn Marino }
3445e4b17023SJohn Marino remove_edge_and_dominated_blocks (entry_succ_e);
3446e4b17023SJohn Marino }
3447e4b17023SJohn Marino else
3448e4b17023SJohn Marino {
3449e4b17023SJohn Marino unsigned srcidx, dstidx, num;
3450e4b17023SJohn Marino
3451e4b17023SJohn Marino /* If the parallel region needs data sent from the parent
3452e4b17023SJohn Marino function, then the very first statement (except possible
3453e4b17023SJohn Marino tree profile counter updates) of the parallel body
3454e4b17023SJohn Marino is a copy assignment .OMP_DATA_I = &.OMP_DATA_O. Since
3455e4b17023SJohn Marino &.OMP_DATA_O is passed as an argument to the child function,
3456e4b17023SJohn Marino we need to replace it with the argument as seen by the child
3457e4b17023SJohn Marino function.
3458e4b17023SJohn Marino
3459e4b17023SJohn Marino In most cases, this will end up being the identity assignment
3460e4b17023SJohn Marino .OMP_DATA_I = .OMP_DATA_I. However, if the parallel body had
3461e4b17023SJohn Marino a function call that has been inlined, the original PARM_DECL
3462e4b17023SJohn Marino .OMP_DATA_I may have been converted into a different local
3463e4b17023SJohn Marino variable. In which case, we need to keep the assignment. */
3464e4b17023SJohn Marino if (gimple_omp_taskreg_data_arg (entry_stmt))
3465e4b17023SJohn Marino {
3466e4b17023SJohn Marino basic_block entry_succ_bb = single_succ (entry_bb);
3467e4b17023SJohn Marino gimple_stmt_iterator gsi;
3468e4b17023SJohn Marino tree arg, narg;
3469e4b17023SJohn Marino gimple parcopy_stmt = NULL;
3470e4b17023SJohn Marino
3471e4b17023SJohn Marino for (gsi = gsi_start_bb (entry_succ_bb); ; gsi_next (&gsi))
3472e4b17023SJohn Marino {
3473e4b17023SJohn Marino gimple stmt;
3474e4b17023SJohn Marino
3475e4b17023SJohn Marino gcc_assert (!gsi_end_p (gsi));
3476e4b17023SJohn Marino stmt = gsi_stmt (gsi);
3477e4b17023SJohn Marino if (gimple_code (stmt) != GIMPLE_ASSIGN)
3478e4b17023SJohn Marino continue;
3479e4b17023SJohn Marino
3480e4b17023SJohn Marino if (gimple_num_ops (stmt) == 2)
3481e4b17023SJohn Marino {
3482e4b17023SJohn Marino tree arg = gimple_assign_rhs1 (stmt);
3483e4b17023SJohn Marino
3484e4b17023SJohn Marino /* We're ignore the subcode because we're
3485e4b17023SJohn Marino effectively doing a STRIP_NOPS. */
3486e4b17023SJohn Marino
3487e4b17023SJohn Marino if (TREE_CODE (arg) == ADDR_EXPR
3488e4b17023SJohn Marino && TREE_OPERAND (arg, 0)
3489e4b17023SJohn Marino == gimple_omp_taskreg_data_arg (entry_stmt))
3490e4b17023SJohn Marino {
3491e4b17023SJohn Marino parcopy_stmt = stmt;
3492e4b17023SJohn Marino break;
3493e4b17023SJohn Marino }
3494e4b17023SJohn Marino }
3495e4b17023SJohn Marino }
3496e4b17023SJohn Marino
3497e4b17023SJohn Marino gcc_assert (parcopy_stmt != NULL);
3498e4b17023SJohn Marino arg = DECL_ARGUMENTS (child_fn);
3499e4b17023SJohn Marino
3500e4b17023SJohn Marino if (!gimple_in_ssa_p (cfun))
3501e4b17023SJohn Marino {
3502e4b17023SJohn Marino if (gimple_assign_lhs (parcopy_stmt) == arg)
3503e4b17023SJohn Marino gsi_remove (&gsi, true);
3504e4b17023SJohn Marino else
3505e4b17023SJohn Marino {
3506e4b17023SJohn Marino /* ?? Is setting the subcode really necessary ?? */
3507e4b17023SJohn Marino gimple_omp_set_subcode (parcopy_stmt, TREE_CODE (arg));
3508e4b17023SJohn Marino gimple_assign_set_rhs1 (parcopy_stmt, arg);
3509e4b17023SJohn Marino }
3510e4b17023SJohn Marino }
3511e4b17023SJohn Marino else
3512e4b17023SJohn Marino {
3513e4b17023SJohn Marino /* If we are in ssa form, we must load the value from the default
3514e4b17023SJohn Marino definition of the argument. That should not be defined now,
3515e4b17023SJohn Marino since the argument is not used uninitialized. */
3516e4b17023SJohn Marino gcc_assert (gimple_default_def (cfun, arg) == NULL);
3517e4b17023SJohn Marino narg = make_ssa_name (arg, gimple_build_nop ());
3518e4b17023SJohn Marino set_default_def (arg, narg);
3519e4b17023SJohn Marino /* ?? Is setting the subcode really necessary ?? */
3520e4b17023SJohn Marino gimple_omp_set_subcode (parcopy_stmt, TREE_CODE (narg));
3521e4b17023SJohn Marino gimple_assign_set_rhs1 (parcopy_stmt, narg);
3522e4b17023SJohn Marino update_stmt (parcopy_stmt);
3523e4b17023SJohn Marino }
3524e4b17023SJohn Marino }
3525e4b17023SJohn Marino
3526e4b17023SJohn Marino /* Declare local variables needed in CHILD_CFUN. */
3527e4b17023SJohn Marino block = DECL_INITIAL (child_fn);
3528e4b17023SJohn Marino BLOCK_VARS (block) = vec2chain (child_cfun->local_decls);
3529e4b17023SJohn Marino /* The gimplifier could record temporaries in parallel/task block
3530e4b17023SJohn Marino rather than in containing function's local_decls chain,
3531e4b17023SJohn Marino which would mean cgraph missed finalizing them. Do it now. */
3532e4b17023SJohn Marino for (t = BLOCK_VARS (block); t; t = DECL_CHAIN (t))
3533e4b17023SJohn Marino if (TREE_CODE (t) == VAR_DECL
3534e4b17023SJohn Marino && TREE_STATIC (t)
3535e4b17023SJohn Marino && !DECL_EXTERNAL (t))
3536e4b17023SJohn Marino varpool_finalize_decl (t);
3537e4b17023SJohn Marino DECL_SAVED_TREE (child_fn) = NULL;
3538e4b17023SJohn Marino gimple_set_body (child_fn, bb_seq (single_succ (entry_bb)));
3539e4b17023SJohn Marino TREE_USED (block) = 1;
3540e4b17023SJohn Marino
3541e4b17023SJohn Marino /* Reset DECL_CONTEXT on function arguments. */
3542e4b17023SJohn Marino for (t = DECL_ARGUMENTS (child_fn); t; t = DECL_CHAIN (t))
3543e4b17023SJohn Marino DECL_CONTEXT (t) = child_fn;
3544e4b17023SJohn Marino
3545e4b17023SJohn Marino /* Split ENTRY_BB at GIMPLE_OMP_PARALLEL or GIMPLE_OMP_TASK,
3546e4b17023SJohn Marino so that it can be moved to the child function. */
3547e4b17023SJohn Marino gsi = gsi_last_bb (entry_bb);
3548e4b17023SJohn Marino stmt = gsi_stmt (gsi);
3549e4b17023SJohn Marino gcc_assert (stmt && (gimple_code (stmt) == GIMPLE_OMP_PARALLEL
3550e4b17023SJohn Marino || gimple_code (stmt) == GIMPLE_OMP_TASK));
3551e4b17023SJohn Marino gsi_remove (&gsi, true);
3552e4b17023SJohn Marino e = split_block (entry_bb, stmt);
3553e4b17023SJohn Marino entry_bb = e->dest;
3554e4b17023SJohn Marino single_succ_edge (entry_bb)->flags = EDGE_FALLTHRU;
3555e4b17023SJohn Marino
3556e4b17023SJohn Marino /* Convert GIMPLE_OMP_RETURN into a RETURN_EXPR. */
3557e4b17023SJohn Marino if (exit_bb)
3558e4b17023SJohn Marino {
3559e4b17023SJohn Marino gsi = gsi_last_bb (exit_bb);
3560e4b17023SJohn Marino gcc_assert (!gsi_end_p (gsi)
3561e4b17023SJohn Marino && gimple_code (gsi_stmt (gsi)) == GIMPLE_OMP_RETURN);
3562e4b17023SJohn Marino stmt = gimple_build_return (NULL);
3563e4b17023SJohn Marino gsi_insert_after (&gsi, stmt, GSI_SAME_STMT);
3564e4b17023SJohn Marino gsi_remove (&gsi, true);
3565e4b17023SJohn Marino }
3566e4b17023SJohn Marino
3567e4b17023SJohn Marino /* Move the parallel region into CHILD_CFUN. */
3568e4b17023SJohn Marino
3569e4b17023SJohn Marino if (gimple_in_ssa_p (cfun))
3570e4b17023SJohn Marino {
3571e4b17023SJohn Marino push_cfun (child_cfun);
3572e4b17023SJohn Marino init_tree_ssa (child_cfun);
3573e4b17023SJohn Marino init_ssa_operands ();
3574e4b17023SJohn Marino cfun->gimple_df->in_ssa_p = true;
3575e4b17023SJohn Marino pop_cfun ();
3576e4b17023SJohn Marino block = NULL_TREE;
3577e4b17023SJohn Marino }
3578e4b17023SJohn Marino else
3579e4b17023SJohn Marino block = gimple_block (entry_stmt);
3580e4b17023SJohn Marino
3581e4b17023SJohn Marino new_bb = move_sese_region_to_fn (child_cfun, entry_bb, exit_bb, block);
3582e4b17023SJohn Marino if (exit_bb)
3583e4b17023SJohn Marino single_succ_edge (new_bb)->flags = EDGE_FALLTHRU;
3584e4b17023SJohn Marino
3585e4b17023SJohn Marino /* Remove non-local VAR_DECLs from child_cfun->local_decls list. */
3586e4b17023SJohn Marino num = VEC_length (tree, child_cfun->local_decls);
3587e4b17023SJohn Marino for (srcidx = 0, dstidx = 0; srcidx < num; srcidx++)
3588e4b17023SJohn Marino {
3589e4b17023SJohn Marino t = VEC_index (tree, child_cfun->local_decls, srcidx);
3590e4b17023SJohn Marino if (DECL_CONTEXT (t) == cfun->decl)
3591e4b17023SJohn Marino continue;
3592e4b17023SJohn Marino if (srcidx != dstidx)
3593e4b17023SJohn Marino VEC_replace (tree, child_cfun->local_decls, dstidx, t);
3594e4b17023SJohn Marino dstidx++;
3595e4b17023SJohn Marino }
3596e4b17023SJohn Marino if (dstidx != num)
3597e4b17023SJohn Marino VEC_truncate (tree, child_cfun->local_decls, dstidx);
3598e4b17023SJohn Marino
3599e4b17023SJohn Marino /* Inform the callgraph about the new function. */
3600e4b17023SJohn Marino DECL_STRUCT_FUNCTION (child_fn)->curr_properties
3601e4b17023SJohn Marino = cfun->curr_properties;
3602e4b17023SJohn Marino cgraph_add_new_function (child_fn, true);
3603e4b17023SJohn Marino
3604e4b17023SJohn Marino /* Fix the callgraph edges for child_cfun. Those for cfun will be
3605e4b17023SJohn Marino fixed in a following pass. */
3606e4b17023SJohn Marino push_cfun (child_cfun);
3607e4b17023SJohn Marino save_current = current_function_decl;
3608e4b17023SJohn Marino current_function_decl = child_fn;
3609e4b17023SJohn Marino if (optimize)
3610e4b17023SJohn Marino optimize_omp_library_calls (entry_stmt);
3611e4b17023SJohn Marino rebuild_cgraph_edges ();
3612e4b17023SJohn Marino
3613e4b17023SJohn Marino /* Some EH regions might become dead, see PR34608. If
3614e4b17023SJohn Marino pass_cleanup_cfg isn't the first pass to happen with the
3615e4b17023SJohn Marino new child, these dead EH edges might cause problems.
3616e4b17023SJohn Marino Clean them up now. */
3617e4b17023SJohn Marino if (flag_exceptions)
3618e4b17023SJohn Marino {
3619e4b17023SJohn Marino basic_block bb;
3620e4b17023SJohn Marino bool changed = false;
3621e4b17023SJohn Marino
3622e4b17023SJohn Marino FOR_EACH_BB (bb)
3623e4b17023SJohn Marino changed |= gimple_purge_dead_eh_edges (bb);
3624e4b17023SJohn Marino if (changed)
3625e4b17023SJohn Marino cleanup_tree_cfg ();
3626e4b17023SJohn Marino }
3627e4b17023SJohn Marino if (gimple_in_ssa_p (cfun))
3628e4b17023SJohn Marino update_ssa (TODO_update_ssa);
3629e4b17023SJohn Marino current_function_decl = save_current;
3630e4b17023SJohn Marino pop_cfun ();
3631e4b17023SJohn Marino }
3632e4b17023SJohn Marino
3633e4b17023SJohn Marino /* Emit a library call to launch the children threads. */
3634e4b17023SJohn Marino if (gimple_code (entry_stmt) == GIMPLE_OMP_PARALLEL)
3635e4b17023SJohn Marino expand_parallel_call (region, new_bb, entry_stmt, ws_args);
3636e4b17023SJohn Marino else
3637e4b17023SJohn Marino expand_task_call (new_bb, entry_stmt);
3638e4b17023SJohn Marino update_ssa (TODO_update_ssa_only_virtuals);
3639e4b17023SJohn Marino }
3640e4b17023SJohn Marino
3641e4b17023SJohn Marino
3642e4b17023SJohn Marino /* A subroutine of expand_omp_for. Generate code for a parallel
3643e4b17023SJohn Marino loop with any schedule. Given parameters:
3644e4b17023SJohn Marino
3645e4b17023SJohn Marino for (V = N1; V cond N2; V += STEP) BODY;
3646e4b17023SJohn Marino
3647e4b17023SJohn Marino where COND is "<" or ">", we generate pseudocode
3648e4b17023SJohn Marino
3649e4b17023SJohn Marino more = GOMP_loop_foo_start (N1, N2, STEP, CHUNK, &istart0, &iend0);
3650e4b17023SJohn Marino if (more) goto L0; else goto L3;
3651e4b17023SJohn Marino L0:
3652e4b17023SJohn Marino V = istart0;
3653e4b17023SJohn Marino iend = iend0;
3654e4b17023SJohn Marino L1:
3655e4b17023SJohn Marino BODY;
3656e4b17023SJohn Marino V += STEP;
3657e4b17023SJohn Marino if (V cond iend) goto L1; else goto L2;
3658e4b17023SJohn Marino L2:
3659e4b17023SJohn Marino if (GOMP_loop_foo_next (&istart0, &iend0)) goto L0; else goto L3;
3660e4b17023SJohn Marino L3:
3661e4b17023SJohn Marino
3662e4b17023SJohn Marino If this is a combined omp parallel loop, instead of the call to
3663e4b17023SJohn Marino GOMP_loop_foo_start, we call GOMP_loop_foo_next.
3664e4b17023SJohn Marino
3665e4b17023SJohn Marino For collapsed loops, given parameters:
3666e4b17023SJohn Marino collapse(3)
3667e4b17023SJohn Marino for (V1 = N11; V1 cond1 N12; V1 += STEP1)
3668e4b17023SJohn Marino for (V2 = N21; V2 cond2 N22; V2 += STEP2)
3669e4b17023SJohn Marino for (V3 = N31; V3 cond3 N32; V3 += STEP3)
3670e4b17023SJohn Marino BODY;
3671e4b17023SJohn Marino
3672e4b17023SJohn Marino we generate pseudocode
3673e4b17023SJohn Marino
3674e4b17023SJohn Marino if (cond3 is <)
3675e4b17023SJohn Marino adj = STEP3 - 1;
3676e4b17023SJohn Marino else
3677e4b17023SJohn Marino adj = STEP3 + 1;
3678e4b17023SJohn Marino count3 = (adj + N32 - N31) / STEP3;
3679e4b17023SJohn Marino if (cond2 is <)
3680e4b17023SJohn Marino adj = STEP2 - 1;
3681e4b17023SJohn Marino else
3682e4b17023SJohn Marino adj = STEP2 + 1;
3683e4b17023SJohn Marino count2 = (adj + N22 - N21) / STEP2;
3684e4b17023SJohn Marino if (cond1 is <)
3685e4b17023SJohn Marino adj = STEP1 - 1;
3686e4b17023SJohn Marino else
3687e4b17023SJohn Marino adj = STEP1 + 1;
3688e4b17023SJohn Marino count1 = (adj + N12 - N11) / STEP1;
3689e4b17023SJohn Marino count = count1 * count2 * count3;
3690e4b17023SJohn Marino more = GOMP_loop_foo_start (0, count, 1, CHUNK, &istart0, &iend0);
3691e4b17023SJohn Marino if (more) goto L0; else goto L3;
3692e4b17023SJohn Marino L0:
3693e4b17023SJohn Marino V = istart0;
3694e4b17023SJohn Marino T = V;
3695e4b17023SJohn Marino V3 = N31 + (T % count3) * STEP3;
3696e4b17023SJohn Marino T = T / count3;
3697e4b17023SJohn Marino V2 = N21 + (T % count2) * STEP2;
3698e4b17023SJohn Marino T = T / count2;
3699e4b17023SJohn Marino V1 = N11 + T * STEP1;
3700e4b17023SJohn Marino iend = iend0;
3701e4b17023SJohn Marino L1:
3702e4b17023SJohn Marino BODY;
3703e4b17023SJohn Marino V += 1;
3704e4b17023SJohn Marino if (V < iend) goto L10; else goto L2;
3705e4b17023SJohn Marino L10:
3706e4b17023SJohn Marino V3 += STEP3;
3707e4b17023SJohn Marino if (V3 cond3 N32) goto L1; else goto L11;
3708e4b17023SJohn Marino L11:
3709e4b17023SJohn Marino V3 = N31;
3710e4b17023SJohn Marino V2 += STEP2;
3711e4b17023SJohn Marino if (V2 cond2 N22) goto L1; else goto L12;
3712e4b17023SJohn Marino L12:
3713e4b17023SJohn Marino V2 = N21;
3714e4b17023SJohn Marino V1 += STEP1;
3715e4b17023SJohn Marino goto L1;
3716e4b17023SJohn Marino L2:
3717e4b17023SJohn Marino if (GOMP_loop_foo_next (&istart0, &iend0)) goto L0; else goto L3;
3718e4b17023SJohn Marino L3:
3719e4b17023SJohn Marino
3720e4b17023SJohn Marino */
3721e4b17023SJohn Marino
3722e4b17023SJohn Marino static void
expand_omp_for_generic(struct omp_region * region,struct omp_for_data * fd,enum built_in_function start_fn,enum built_in_function next_fn)3723e4b17023SJohn Marino expand_omp_for_generic (struct omp_region *region,
3724e4b17023SJohn Marino struct omp_for_data *fd,
3725e4b17023SJohn Marino enum built_in_function start_fn,
3726e4b17023SJohn Marino enum built_in_function next_fn)
3727e4b17023SJohn Marino {
3728e4b17023SJohn Marino tree type, istart0, iend0, iend;
3729e4b17023SJohn Marino tree t, vmain, vback, bias = NULL_TREE;
3730e4b17023SJohn Marino basic_block entry_bb, cont_bb, exit_bb, l0_bb, l1_bb, collapse_bb;
3731e4b17023SJohn Marino basic_block l2_bb = NULL, l3_bb = NULL;
3732e4b17023SJohn Marino gimple_stmt_iterator gsi;
3733e4b17023SJohn Marino gimple stmt;
3734e4b17023SJohn Marino bool in_combined_parallel = is_combined_parallel (region);
3735e4b17023SJohn Marino bool broken_loop = region->cont == NULL;
3736e4b17023SJohn Marino edge e, ne;
3737e4b17023SJohn Marino tree *counts = NULL;
3738e4b17023SJohn Marino int i;
3739e4b17023SJohn Marino
3740e4b17023SJohn Marino gcc_assert (!broken_loop || !in_combined_parallel);
3741e4b17023SJohn Marino gcc_assert (fd->iter_type == long_integer_type_node
3742e4b17023SJohn Marino || !in_combined_parallel);
3743e4b17023SJohn Marino
3744e4b17023SJohn Marino type = TREE_TYPE (fd->loop.v);
3745e4b17023SJohn Marino istart0 = create_tmp_var (fd->iter_type, ".istart0");
3746e4b17023SJohn Marino iend0 = create_tmp_var (fd->iter_type, ".iend0");
3747e4b17023SJohn Marino TREE_ADDRESSABLE (istart0) = 1;
3748e4b17023SJohn Marino TREE_ADDRESSABLE (iend0) = 1;
3749e4b17023SJohn Marino if (gimple_in_ssa_p (cfun))
3750e4b17023SJohn Marino {
3751e4b17023SJohn Marino add_referenced_var (istart0);
3752e4b17023SJohn Marino add_referenced_var (iend0);
3753e4b17023SJohn Marino }
3754e4b17023SJohn Marino
3755e4b17023SJohn Marino /* See if we need to bias by LLONG_MIN. */
3756e4b17023SJohn Marino if (fd->iter_type == long_long_unsigned_type_node
3757e4b17023SJohn Marino && TREE_CODE (type) == INTEGER_TYPE
3758e4b17023SJohn Marino && !TYPE_UNSIGNED (type))
3759e4b17023SJohn Marino {
3760e4b17023SJohn Marino tree n1, n2;
3761e4b17023SJohn Marino
3762e4b17023SJohn Marino if (fd->loop.cond_code == LT_EXPR)
3763e4b17023SJohn Marino {
3764e4b17023SJohn Marino n1 = fd->loop.n1;
3765e4b17023SJohn Marino n2 = fold_build2 (PLUS_EXPR, type, fd->loop.n2, fd->loop.step);
3766e4b17023SJohn Marino }
3767e4b17023SJohn Marino else
3768e4b17023SJohn Marino {
3769e4b17023SJohn Marino n1 = fold_build2 (MINUS_EXPR, type, fd->loop.n2, fd->loop.step);
3770e4b17023SJohn Marino n2 = fd->loop.n1;
3771e4b17023SJohn Marino }
3772e4b17023SJohn Marino if (TREE_CODE (n1) != INTEGER_CST
3773e4b17023SJohn Marino || TREE_CODE (n2) != INTEGER_CST
3774e4b17023SJohn Marino || ((tree_int_cst_sgn (n1) < 0) ^ (tree_int_cst_sgn (n2) < 0)))
3775e4b17023SJohn Marino bias = fold_convert (fd->iter_type, TYPE_MIN_VALUE (type));
3776e4b17023SJohn Marino }
3777e4b17023SJohn Marino
3778e4b17023SJohn Marino entry_bb = region->entry;
3779e4b17023SJohn Marino cont_bb = region->cont;
3780e4b17023SJohn Marino collapse_bb = NULL;
3781e4b17023SJohn Marino gcc_assert (EDGE_COUNT (entry_bb->succs) == 2);
3782e4b17023SJohn Marino gcc_assert (broken_loop
3783e4b17023SJohn Marino || BRANCH_EDGE (entry_bb)->dest == FALLTHRU_EDGE (cont_bb)->dest);
3784e4b17023SJohn Marino l0_bb = split_edge (FALLTHRU_EDGE (entry_bb));
3785e4b17023SJohn Marino l1_bb = single_succ (l0_bb);
3786e4b17023SJohn Marino if (!broken_loop)
3787e4b17023SJohn Marino {
3788e4b17023SJohn Marino l2_bb = create_empty_bb (cont_bb);
3789e4b17023SJohn Marino gcc_assert (BRANCH_EDGE (cont_bb)->dest == l1_bb);
3790e4b17023SJohn Marino gcc_assert (EDGE_COUNT (cont_bb->succs) == 2);
3791e4b17023SJohn Marino }
3792e4b17023SJohn Marino else
3793e4b17023SJohn Marino l2_bb = NULL;
3794e4b17023SJohn Marino l3_bb = BRANCH_EDGE (entry_bb)->dest;
3795e4b17023SJohn Marino exit_bb = region->exit;
3796e4b17023SJohn Marino
3797e4b17023SJohn Marino gsi = gsi_last_bb (entry_bb);
3798e4b17023SJohn Marino
3799e4b17023SJohn Marino gcc_assert (gimple_code (gsi_stmt (gsi)) == GIMPLE_OMP_FOR);
3800e4b17023SJohn Marino if (fd->collapse > 1)
3801e4b17023SJohn Marino {
3802e4b17023SJohn Marino /* collapsed loops need work for expansion in SSA form. */
3803e4b17023SJohn Marino gcc_assert (!gimple_in_ssa_p (cfun));
3804e4b17023SJohn Marino counts = (tree *) alloca (fd->collapse * sizeof (tree));
3805e4b17023SJohn Marino for (i = 0; i < fd->collapse; i++)
3806e4b17023SJohn Marino {
3807e4b17023SJohn Marino tree itype = TREE_TYPE (fd->loops[i].v);
3808e4b17023SJohn Marino
3809e4b17023SJohn Marino if (POINTER_TYPE_P (itype))
3810e4b17023SJohn Marino itype = lang_hooks.types.type_for_size (TYPE_PRECISION (itype), 0);
3811e4b17023SJohn Marino t = build_int_cst (itype, (fd->loops[i].cond_code == LT_EXPR
3812e4b17023SJohn Marino ? -1 : 1));
3813e4b17023SJohn Marino t = fold_build2 (PLUS_EXPR, itype,
3814e4b17023SJohn Marino fold_convert (itype, fd->loops[i].step), t);
3815e4b17023SJohn Marino t = fold_build2 (PLUS_EXPR, itype, t,
3816e4b17023SJohn Marino fold_convert (itype, fd->loops[i].n2));
3817e4b17023SJohn Marino t = fold_build2 (MINUS_EXPR, itype, t,
3818e4b17023SJohn Marino fold_convert (itype, fd->loops[i].n1));
3819e4b17023SJohn Marino if (TYPE_UNSIGNED (itype) && fd->loops[i].cond_code == GT_EXPR)
3820e4b17023SJohn Marino t = fold_build2 (TRUNC_DIV_EXPR, itype,
3821e4b17023SJohn Marino fold_build1 (NEGATE_EXPR, itype, t),
3822e4b17023SJohn Marino fold_build1 (NEGATE_EXPR, itype,
3823e4b17023SJohn Marino fold_convert (itype,
3824e4b17023SJohn Marino fd->loops[i].step)));
3825e4b17023SJohn Marino else
3826e4b17023SJohn Marino t = fold_build2 (TRUNC_DIV_EXPR, itype, t,
3827e4b17023SJohn Marino fold_convert (itype, fd->loops[i].step));
3828e4b17023SJohn Marino t = fold_convert (type, t);
3829e4b17023SJohn Marino if (TREE_CODE (t) == INTEGER_CST)
3830e4b17023SJohn Marino counts[i] = t;
3831e4b17023SJohn Marino else
3832e4b17023SJohn Marino {
3833e4b17023SJohn Marino counts[i] = create_tmp_var (type, ".count");
3834e4b17023SJohn Marino t = force_gimple_operand_gsi (&gsi, t, false, NULL_TREE,
3835e4b17023SJohn Marino true, GSI_SAME_STMT);
3836e4b17023SJohn Marino stmt = gimple_build_assign (counts[i], t);
3837e4b17023SJohn Marino gsi_insert_before (&gsi, stmt, GSI_SAME_STMT);
3838e4b17023SJohn Marino }
3839e4b17023SJohn Marino if (SSA_VAR_P (fd->loop.n2))
3840e4b17023SJohn Marino {
3841e4b17023SJohn Marino if (i == 0)
3842e4b17023SJohn Marino t = counts[0];
3843e4b17023SJohn Marino else
3844e4b17023SJohn Marino {
3845e4b17023SJohn Marino t = fold_build2 (MULT_EXPR, type, fd->loop.n2, counts[i]);
3846e4b17023SJohn Marino t = force_gimple_operand_gsi (&gsi, t, false, NULL_TREE,
3847e4b17023SJohn Marino true, GSI_SAME_STMT);
3848e4b17023SJohn Marino }
3849e4b17023SJohn Marino stmt = gimple_build_assign (fd->loop.n2, t);
3850e4b17023SJohn Marino gsi_insert_before (&gsi, stmt, GSI_SAME_STMT);
3851e4b17023SJohn Marino }
3852e4b17023SJohn Marino }
3853e4b17023SJohn Marino }
3854e4b17023SJohn Marino if (in_combined_parallel)
3855e4b17023SJohn Marino {
3856e4b17023SJohn Marino /* In a combined parallel loop, emit a call to
3857e4b17023SJohn Marino GOMP_loop_foo_next. */
3858e4b17023SJohn Marino t = build_call_expr (builtin_decl_explicit (next_fn), 2,
3859e4b17023SJohn Marino build_fold_addr_expr (istart0),
3860e4b17023SJohn Marino build_fold_addr_expr (iend0));
3861e4b17023SJohn Marino }
3862e4b17023SJohn Marino else
3863e4b17023SJohn Marino {
3864e4b17023SJohn Marino tree t0, t1, t2, t3, t4;
3865e4b17023SJohn Marino /* If this is not a combined parallel loop, emit a call to
3866e4b17023SJohn Marino GOMP_loop_foo_start in ENTRY_BB. */
3867e4b17023SJohn Marino t4 = build_fold_addr_expr (iend0);
3868e4b17023SJohn Marino t3 = build_fold_addr_expr (istart0);
3869e4b17023SJohn Marino t2 = fold_convert (fd->iter_type, fd->loop.step);
3870e4b17023SJohn Marino if (POINTER_TYPE_P (type)
3871e4b17023SJohn Marino && TYPE_PRECISION (type) != TYPE_PRECISION (fd->iter_type))
3872e4b17023SJohn Marino {
3873e4b17023SJohn Marino /* Avoid casting pointers to integer of a different size. */
3874e4b17023SJohn Marino tree itype
3875e4b17023SJohn Marino = lang_hooks.types.type_for_size (TYPE_PRECISION (type), 0);
3876e4b17023SJohn Marino t1 = fold_convert (fd->iter_type, fold_convert (itype, fd->loop.n2));
3877e4b17023SJohn Marino t0 = fold_convert (fd->iter_type, fold_convert (itype, fd->loop.n1));
3878e4b17023SJohn Marino }
3879e4b17023SJohn Marino else
3880e4b17023SJohn Marino {
3881e4b17023SJohn Marino t1 = fold_convert (fd->iter_type, fd->loop.n2);
3882e4b17023SJohn Marino t0 = fold_convert (fd->iter_type, fd->loop.n1);
3883e4b17023SJohn Marino }
3884e4b17023SJohn Marino if (bias)
3885e4b17023SJohn Marino {
3886e4b17023SJohn Marino t1 = fold_build2 (PLUS_EXPR, fd->iter_type, t1, bias);
3887e4b17023SJohn Marino t0 = fold_build2 (PLUS_EXPR, fd->iter_type, t0, bias);
3888e4b17023SJohn Marino }
3889e4b17023SJohn Marino if (fd->iter_type == long_integer_type_node)
3890e4b17023SJohn Marino {
3891e4b17023SJohn Marino if (fd->chunk_size)
3892e4b17023SJohn Marino {
3893e4b17023SJohn Marino t = fold_convert (fd->iter_type, fd->chunk_size);
3894e4b17023SJohn Marino t = build_call_expr (builtin_decl_explicit (start_fn),
3895e4b17023SJohn Marino 6, t0, t1, t2, t, t3, t4);
3896e4b17023SJohn Marino }
3897e4b17023SJohn Marino else
3898e4b17023SJohn Marino t = build_call_expr (builtin_decl_explicit (start_fn),
3899e4b17023SJohn Marino 5, t0, t1, t2, t3, t4);
3900e4b17023SJohn Marino }
3901e4b17023SJohn Marino else
3902e4b17023SJohn Marino {
3903e4b17023SJohn Marino tree t5;
3904e4b17023SJohn Marino tree c_bool_type;
3905e4b17023SJohn Marino tree bfn_decl;
3906e4b17023SJohn Marino
3907e4b17023SJohn Marino /* The GOMP_loop_ull_*start functions have additional boolean
3908e4b17023SJohn Marino argument, true for < loops and false for > loops.
3909e4b17023SJohn Marino In Fortran, the C bool type can be different from
3910e4b17023SJohn Marino boolean_type_node. */
3911e4b17023SJohn Marino bfn_decl = builtin_decl_explicit (start_fn);
3912e4b17023SJohn Marino c_bool_type = TREE_TYPE (TREE_TYPE (bfn_decl));
3913e4b17023SJohn Marino t5 = build_int_cst (c_bool_type,
3914e4b17023SJohn Marino fd->loop.cond_code == LT_EXPR ? 1 : 0);
3915e4b17023SJohn Marino if (fd->chunk_size)
3916e4b17023SJohn Marino {
3917e4b17023SJohn Marino tree bfn_decl = builtin_decl_explicit (start_fn);
3918e4b17023SJohn Marino t = fold_convert (fd->iter_type, fd->chunk_size);
3919e4b17023SJohn Marino t = build_call_expr (bfn_decl, 7, t5, t0, t1, t2, t, t3, t4);
3920e4b17023SJohn Marino }
3921e4b17023SJohn Marino else
3922e4b17023SJohn Marino t = build_call_expr (builtin_decl_explicit (start_fn),
3923e4b17023SJohn Marino 6, t5, t0, t1, t2, t3, t4);
3924e4b17023SJohn Marino }
3925e4b17023SJohn Marino }
3926e4b17023SJohn Marino if (TREE_TYPE (t) != boolean_type_node)
3927e4b17023SJohn Marino t = fold_build2 (NE_EXPR, boolean_type_node,
3928e4b17023SJohn Marino t, build_int_cst (TREE_TYPE (t), 0));
3929e4b17023SJohn Marino t = force_gimple_operand_gsi (&gsi, t, true, NULL_TREE,
3930e4b17023SJohn Marino true, GSI_SAME_STMT);
3931e4b17023SJohn Marino gsi_insert_after (&gsi, gimple_build_cond_empty (t), GSI_SAME_STMT);
3932e4b17023SJohn Marino
3933e4b17023SJohn Marino /* Remove the GIMPLE_OMP_FOR statement. */
3934e4b17023SJohn Marino gsi_remove (&gsi, true);
3935e4b17023SJohn Marino
3936e4b17023SJohn Marino /* Iteration setup for sequential loop goes in L0_BB. */
3937e4b17023SJohn Marino gsi = gsi_start_bb (l0_bb);
3938e4b17023SJohn Marino t = istart0;
3939e4b17023SJohn Marino if (bias)
3940e4b17023SJohn Marino t = fold_build2 (MINUS_EXPR, fd->iter_type, t, bias);
3941e4b17023SJohn Marino if (POINTER_TYPE_P (type))
3942e4b17023SJohn Marino t = fold_convert (lang_hooks.types.type_for_size (TYPE_PRECISION (type),
3943e4b17023SJohn Marino 0), t);
3944e4b17023SJohn Marino t = fold_convert (type, t);
3945e4b17023SJohn Marino t = force_gimple_operand_gsi (&gsi, t, false, NULL_TREE,
3946e4b17023SJohn Marino false, GSI_CONTINUE_LINKING);
3947e4b17023SJohn Marino stmt = gimple_build_assign (fd->loop.v, t);
3948e4b17023SJohn Marino gsi_insert_after (&gsi, stmt, GSI_CONTINUE_LINKING);
3949e4b17023SJohn Marino
3950e4b17023SJohn Marino t = iend0;
3951e4b17023SJohn Marino if (bias)
3952e4b17023SJohn Marino t = fold_build2 (MINUS_EXPR, fd->iter_type, t, bias);
3953e4b17023SJohn Marino if (POINTER_TYPE_P (type))
3954e4b17023SJohn Marino t = fold_convert (lang_hooks.types.type_for_size (TYPE_PRECISION (type),
3955e4b17023SJohn Marino 0), t);
3956e4b17023SJohn Marino t = fold_convert (type, t);
3957e4b17023SJohn Marino iend = force_gimple_operand_gsi (&gsi, t, true, NULL_TREE,
3958e4b17023SJohn Marino false, GSI_CONTINUE_LINKING);
3959e4b17023SJohn Marino if (fd->collapse > 1)
3960e4b17023SJohn Marino {
3961e4b17023SJohn Marino tree tem = create_tmp_var (type, ".tem");
3962e4b17023SJohn Marino
3963e4b17023SJohn Marino stmt = gimple_build_assign (tem, fd->loop.v);
3964e4b17023SJohn Marino gsi_insert_after (&gsi, stmt, GSI_CONTINUE_LINKING);
3965e4b17023SJohn Marino for (i = fd->collapse - 1; i >= 0; i--)
3966e4b17023SJohn Marino {
3967e4b17023SJohn Marino tree vtype = TREE_TYPE (fd->loops[i].v), itype;
3968e4b17023SJohn Marino itype = vtype;
3969e4b17023SJohn Marino if (POINTER_TYPE_P (vtype))
3970e4b17023SJohn Marino itype = lang_hooks.types.type_for_size (TYPE_PRECISION (vtype), 0);
3971e4b17023SJohn Marino t = fold_build2 (TRUNC_MOD_EXPR, type, tem, counts[i]);
3972e4b17023SJohn Marino t = fold_convert (itype, t);
3973e4b17023SJohn Marino t = fold_build2 (MULT_EXPR, itype, t,
3974e4b17023SJohn Marino fold_convert (itype, fd->loops[i].step));
3975e4b17023SJohn Marino if (POINTER_TYPE_P (vtype))
3976e4b17023SJohn Marino t = fold_build_pointer_plus (fd->loops[i].n1, t);
3977e4b17023SJohn Marino else
3978e4b17023SJohn Marino t = fold_build2 (PLUS_EXPR, itype, fd->loops[i].n1, t);
3979e4b17023SJohn Marino t = force_gimple_operand_gsi (&gsi, t, false, NULL_TREE,
3980e4b17023SJohn Marino false, GSI_CONTINUE_LINKING);
3981e4b17023SJohn Marino stmt = gimple_build_assign (fd->loops[i].v, t);
3982e4b17023SJohn Marino gsi_insert_after (&gsi, stmt, GSI_CONTINUE_LINKING);
3983e4b17023SJohn Marino if (i != 0)
3984e4b17023SJohn Marino {
3985e4b17023SJohn Marino t = fold_build2 (TRUNC_DIV_EXPR, type, tem, counts[i]);
3986e4b17023SJohn Marino t = force_gimple_operand_gsi (&gsi, t, false, NULL_TREE,
3987e4b17023SJohn Marino false, GSI_CONTINUE_LINKING);
3988e4b17023SJohn Marino stmt = gimple_build_assign (tem, t);
3989e4b17023SJohn Marino gsi_insert_after (&gsi, stmt, GSI_CONTINUE_LINKING);
3990e4b17023SJohn Marino }
3991e4b17023SJohn Marino }
3992e4b17023SJohn Marino }
3993e4b17023SJohn Marino
3994e4b17023SJohn Marino if (!broken_loop)
3995e4b17023SJohn Marino {
3996e4b17023SJohn Marino /* Code to control the increment and predicate for the sequential
3997e4b17023SJohn Marino loop goes in the CONT_BB. */
3998e4b17023SJohn Marino gsi = gsi_last_bb (cont_bb);
3999e4b17023SJohn Marino stmt = gsi_stmt (gsi);
4000e4b17023SJohn Marino gcc_assert (gimple_code (stmt) == GIMPLE_OMP_CONTINUE);
4001e4b17023SJohn Marino vmain = gimple_omp_continue_control_use (stmt);
4002e4b17023SJohn Marino vback = gimple_omp_continue_control_def (stmt);
4003e4b17023SJohn Marino
4004e4b17023SJohn Marino if (POINTER_TYPE_P (type))
4005e4b17023SJohn Marino t = fold_build_pointer_plus (vmain, fd->loop.step);
4006e4b17023SJohn Marino else
4007e4b17023SJohn Marino t = fold_build2 (PLUS_EXPR, type, vmain, fd->loop.step);
4008e4b17023SJohn Marino t = force_gimple_operand_gsi (&gsi, t, false, NULL_TREE,
4009e4b17023SJohn Marino true, GSI_SAME_STMT);
4010e4b17023SJohn Marino stmt = gimple_build_assign (vback, t);
4011e4b17023SJohn Marino gsi_insert_before (&gsi, stmt, GSI_SAME_STMT);
4012e4b17023SJohn Marino
4013e4b17023SJohn Marino t = build2 (fd->loop.cond_code, boolean_type_node, vback, iend);
4014e4b17023SJohn Marino stmt = gimple_build_cond_empty (t);
4015e4b17023SJohn Marino gsi_insert_before (&gsi, stmt, GSI_SAME_STMT);
4016e4b17023SJohn Marino
4017e4b17023SJohn Marino /* Remove GIMPLE_OMP_CONTINUE. */
4018e4b17023SJohn Marino gsi_remove (&gsi, true);
4019e4b17023SJohn Marino
4020e4b17023SJohn Marino if (fd->collapse > 1)
4021e4b17023SJohn Marino {
4022e4b17023SJohn Marino basic_block last_bb, bb;
4023e4b17023SJohn Marino
4024e4b17023SJohn Marino last_bb = cont_bb;
4025e4b17023SJohn Marino for (i = fd->collapse - 1; i >= 0; i--)
4026e4b17023SJohn Marino {
4027e4b17023SJohn Marino tree vtype = TREE_TYPE (fd->loops[i].v);
4028e4b17023SJohn Marino
4029e4b17023SJohn Marino bb = create_empty_bb (last_bb);
4030e4b17023SJohn Marino gsi = gsi_start_bb (bb);
4031e4b17023SJohn Marino
4032e4b17023SJohn Marino if (i < fd->collapse - 1)
4033e4b17023SJohn Marino {
4034e4b17023SJohn Marino e = make_edge (last_bb, bb, EDGE_FALSE_VALUE);
4035e4b17023SJohn Marino e->probability = REG_BR_PROB_BASE / 8;
4036e4b17023SJohn Marino
4037e4b17023SJohn Marino t = fd->loops[i + 1].n1;
4038e4b17023SJohn Marino t = force_gimple_operand_gsi (&gsi, t, false, NULL_TREE,
4039e4b17023SJohn Marino false, GSI_CONTINUE_LINKING);
4040e4b17023SJohn Marino stmt = gimple_build_assign (fd->loops[i + 1].v, t);
4041e4b17023SJohn Marino gsi_insert_after (&gsi, stmt, GSI_CONTINUE_LINKING);
4042e4b17023SJohn Marino }
4043e4b17023SJohn Marino else
4044e4b17023SJohn Marino collapse_bb = bb;
4045e4b17023SJohn Marino
4046e4b17023SJohn Marino set_immediate_dominator (CDI_DOMINATORS, bb, last_bb);
4047e4b17023SJohn Marino
4048e4b17023SJohn Marino if (POINTER_TYPE_P (vtype))
4049e4b17023SJohn Marino t = fold_build_pointer_plus (fd->loops[i].v, fd->loops[i].step);
4050e4b17023SJohn Marino else
4051e4b17023SJohn Marino t = fold_build2 (PLUS_EXPR, vtype, fd->loops[i].v,
4052e4b17023SJohn Marino fd->loops[i].step);
4053e4b17023SJohn Marino t = force_gimple_operand_gsi (&gsi, t, false, NULL_TREE,
4054e4b17023SJohn Marino false, GSI_CONTINUE_LINKING);
4055e4b17023SJohn Marino stmt = gimple_build_assign (fd->loops[i].v, t);
4056e4b17023SJohn Marino gsi_insert_after (&gsi, stmt, GSI_CONTINUE_LINKING);
4057e4b17023SJohn Marino
4058e4b17023SJohn Marino if (i > 0)
4059e4b17023SJohn Marino {
4060e4b17023SJohn Marino t = fd->loops[i].n2;
4061e4b17023SJohn Marino t = force_gimple_operand_gsi (&gsi, t, true, NULL_TREE,
4062e4b17023SJohn Marino false, GSI_CONTINUE_LINKING);
4063e4b17023SJohn Marino t = fold_build2 (fd->loops[i].cond_code, boolean_type_node,
4064e4b17023SJohn Marino fd->loops[i].v, t);
4065e4b17023SJohn Marino stmt = gimple_build_cond_empty (t);
4066e4b17023SJohn Marino gsi_insert_after (&gsi, stmt, GSI_CONTINUE_LINKING);
4067e4b17023SJohn Marino e = make_edge (bb, l1_bb, EDGE_TRUE_VALUE);
4068e4b17023SJohn Marino e->probability = REG_BR_PROB_BASE * 7 / 8;
4069e4b17023SJohn Marino }
4070e4b17023SJohn Marino else
4071e4b17023SJohn Marino make_edge (bb, l1_bb, EDGE_FALLTHRU);
4072e4b17023SJohn Marino last_bb = bb;
4073e4b17023SJohn Marino }
4074e4b17023SJohn Marino }
4075e4b17023SJohn Marino
4076e4b17023SJohn Marino /* Emit code to get the next parallel iteration in L2_BB. */
4077e4b17023SJohn Marino gsi = gsi_start_bb (l2_bb);
4078e4b17023SJohn Marino
4079e4b17023SJohn Marino t = build_call_expr (builtin_decl_explicit (next_fn), 2,
4080e4b17023SJohn Marino build_fold_addr_expr (istart0),
4081e4b17023SJohn Marino build_fold_addr_expr (iend0));
4082e4b17023SJohn Marino t = force_gimple_operand_gsi (&gsi, t, true, NULL_TREE,
4083e4b17023SJohn Marino false, GSI_CONTINUE_LINKING);
4084e4b17023SJohn Marino if (TREE_TYPE (t) != boolean_type_node)
4085e4b17023SJohn Marino t = fold_build2 (NE_EXPR, boolean_type_node,
4086e4b17023SJohn Marino t, build_int_cst (TREE_TYPE (t), 0));
4087e4b17023SJohn Marino stmt = gimple_build_cond_empty (t);
4088e4b17023SJohn Marino gsi_insert_after (&gsi, stmt, GSI_CONTINUE_LINKING);
4089e4b17023SJohn Marino }
4090e4b17023SJohn Marino
4091e4b17023SJohn Marino /* Add the loop cleanup function. */
4092e4b17023SJohn Marino gsi = gsi_last_bb (exit_bb);
4093e4b17023SJohn Marino if (gimple_omp_return_nowait_p (gsi_stmt (gsi)))
4094e4b17023SJohn Marino t = builtin_decl_explicit (BUILT_IN_GOMP_LOOP_END_NOWAIT);
4095e4b17023SJohn Marino else
4096e4b17023SJohn Marino t = builtin_decl_explicit (BUILT_IN_GOMP_LOOP_END);
4097e4b17023SJohn Marino stmt = gimple_build_call (t, 0);
4098e4b17023SJohn Marino gsi_insert_after (&gsi, stmt, GSI_SAME_STMT);
4099e4b17023SJohn Marino gsi_remove (&gsi, true);
4100e4b17023SJohn Marino
4101e4b17023SJohn Marino /* Connect the new blocks. */
4102e4b17023SJohn Marino find_edge (entry_bb, l0_bb)->flags = EDGE_TRUE_VALUE;
4103e4b17023SJohn Marino find_edge (entry_bb, l3_bb)->flags = EDGE_FALSE_VALUE;
4104e4b17023SJohn Marino
4105e4b17023SJohn Marino if (!broken_loop)
4106e4b17023SJohn Marino {
4107e4b17023SJohn Marino gimple_seq phis;
4108e4b17023SJohn Marino
4109e4b17023SJohn Marino e = find_edge (cont_bb, l3_bb);
4110e4b17023SJohn Marino ne = make_edge (l2_bb, l3_bb, EDGE_FALSE_VALUE);
4111e4b17023SJohn Marino
4112e4b17023SJohn Marino phis = phi_nodes (l3_bb);
4113e4b17023SJohn Marino for (gsi = gsi_start (phis); !gsi_end_p (gsi); gsi_next (&gsi))
4114e4b17023SJohn Marino {
4115e4b17023SJohn Marino gimple phi = gsi_stmt (gsi);
4116e4b17023SJohn Marino SET_USE (PHI_ARG_DEF_PTR_FROM_EDGE (phi, ne),
4117e4b17023SJohn Marino PHI_ARG_DEF_FROM_EDGE (phi, e));
4118e4b17023SJohn Marino }
4119e4b17023SJohn Marino remove_edge (e);
4120e4b17023SJohn Marino
4121e4b17023SJohn Marino make_edge (cont_bb, l2_bb, EDGE_FALSE_VALUE);
4122e4b17023SJohn Marino if (fd->collapse > 1)
4123e4b17023SJohn Marino {
4124e4b17023SJohn Marino e = find_edge (cont_bb, l1_bb);
4125e4b17023SJohn Marino remove_edge (e);
4126e4b17023SJohn Marino e = make_edge (cont_bb, collapse_bb, EDGE_TRUE_VALUE);
4127e4b17023SJohn Marino }
4128e4b17023SJohn Marino else
4129e4b17023SJohn Marino {
4130e4b17023SJohn Marino e = find_edge (cont_bb, l1_bb);
4131e4b17023SJohn Marino e->flags = EDGE_TRUE_VALUE;
4132e4b17023SJohn Marino }
4133e4b17023SJohn Marino e->probability = REG_BR_PROB_BASE * 7 / 8;
4134e4b17023SJohn Marino find_edge (cont_bb, l2_bb)->probability = REG_BR_PROB_BASE / 8;
4135e4b17023SJohn Marino make_edge (l2_bb, l0_bb, EDGE_TRUE_VALUE);
4136e4b17023SJohn Marino
4137e4b17023SJohn Marino set_immediate_dominator (CDI_DOMINATORS, l2_bb,
4138e4b17023SJohn Marino recompute_dominator (CDI_DOMINATORS, l2_bb));
4139e4b17023SJohn Marino set_immediate_dominator (CDI_DOMINATORS, l3_bb,
4140e4b17023SJohn Marino recompute_dominator (CDI_DOMINATORS, l3_bb));
4141e4b17023SJohn Marino set_immediate_dominator (CDI_DOMINATORS, l0_bb,
4142e4b17023SJohn Marino recompute_dominator (CDI_DOMINATORS, l0_bb));
4143e4b17023SJohn Marino set_immediate_dominator (CDI_DOMINATORS, l1_bb,
4144e4b17023SJohn Marino recompute_dominator (CDI_DOMINATORS, l1_bb));
4145e4b17023SJohn Marino }
4146e4b17023SJohn Marino }
4147e4b17023SJohn Marino
4148e4b17023SJohn Marino
4149e4b17023SJohn Marino /* A subroutine of expand_omp_for. Generate code for a parallel
4150e4b17023SJohn Marino loop with static schedule and no specified chunk size. Given
4151e4b17023SJohn Marino parameters:
4152e4b17023SJohn Marino
4153e4b17023SJohn Marino for (V = N1; V cond N2; V += STEP) BODY;
4154e4b17023SJohn Marino
4155e4b17023SJohn Marino where COND is "<" or ">", we generate pseudocode
4156e4b17023SJohn Marino
4157e4b17023SJohn Marino if (cond is <)
4158e4b17023SJohn Marino adj = STEP - 1;
4159e4b17023SJohn Marino else
4160e4b17023SJohn Marino adj = STEP + 1;
4161e4b17023SJohn Marino if ((__typeof (V)) -1 > 0 && cond is >)
4162e4b17023SJohn Marino n = -(adj + N2 - N1) / -STEP;
4163e4b17023SJohn Marino else
4164e4b17023SJohn Marino n = (adj + N2 - N1) / STEP;
4165e4b17023SJohn Marino q = n / nthreads;
4166e4b17023SJohn Marino tt = n % nthreads;
4167e4b17023SJohn Marino if (threadid < tt) goto L3; else goto L4;
4168e4b17023SJohn Marino L3:
4169e4b17023SJohn Marino tt = 0;
4170e4b17023SJohn Marino q = q + 1;
4171e4b17023SJohn Marino L4:
4172e4b17023SJohn Marino s0 = q * threadid + tt;
4173e4b17023SJohn Marino e0 = s0 + q;
4174e4b17023SJohn Marino V = s0 * STEP + N1;
4175e4b17023SJohn Marino if (s0 >= e0) goto L2; else goto L0;
4176e4b17023SJohn Marino L0:
4177e4b17023SJohn Marino e = e0 * STEP + N1;
4178e4b17023SJohn Marino L1:
4179e4b17023SJohn Marino BODY;
4180e4b17023SJohn Marino V += STEP;
4181e4b17023SJohn Marino if (V cond e) goto L1;
4182e4b17023SJohn Marino L2:
4183e4b17023SJohn Marino */
4184e4b17023SJohn Marino
4185e4b17023SJohn Marino static void
expand_omp_for_static_nochunk(struct omp_region * region,struct omp_for_data * fd)4186e4b17023SJohn Marino expand_omp_for_static_nochunk (struct omp_region *region,
4187e4b17023SJohn Marino struct omp_for_data *fd)
4188e4b17023SJohn Marino {
4189e4b17023SJohn Marino tree n, q, s0, e0, e, t, tt, nthreads, threadid;
4190e4b17023SJohn Marino tree type, itype, vmain, vback;
4191e4b17023SJohn Marino basic_block entry_bb, second_bb, third_bb, exit_bb, seq_start_bb;
4192e4b17023SJohn Marino basic_block body_bb, cont_bb;
4193e4b17023SJohn Marino basic_block fin_bb;
4194e4b17023SJohn Marino gimple_stmt_iterator gsi;
4195e4b17023SJohn Marino gimple stmt;
4196e4b17023SJohn Marino edge ep;
4197e4b17023SJohn Marino
4198e4b17023SJohn Marino itype = type = TREE_TYPE (fd->loop.v);
4199e4b17023SJohn Marino if (POINTER_TYPE_P (type))
4200e4b17023SJohn Marino itype = lang_hooks.types.type_for_size (TYPE_PRECISION (type), 0);
4201e4b17023SJohn Marino
4202e4b17023SJohn Marino entry_bb = region->entry;
4203e4b17023SJohn Marino cont_bb = region->cont;
4204e4b17023SJohn Marino gcc_assert (EDGE_COUNT (entry_bb->succs) == 2);
4205e4b17023SJohn Marino gcc_assert (BRANCH_EDGE (entry_bb)->dest == FALLTHRU_EDGE (cont_bb)->dest);
4206e4b17023SJohn Marino seq_start_bb = split_edge (FALLTHRU_EDGE (entry_bb));
4207e4b17023SJohn Marino body_bb = single_succ (seq_start_bb);
4208e4b17023SJohn Marino gcc_assert (BRANCH_EDGE (cont_bb)->dest == body_bb);
4209e4b17023SJohn Marino gcc_assert (EDGE_COUNT (cont_bb->succs) == 2);
4210e4b17023SJohn Marino fin_bb = FALLTHRU_EDGE (cont_bb)->dest;
4211e4b17023SJohn Marino exit_bb = region->exit;
4212e4b17023SJohn Marino
4213e4b17023SJohn Marino /* Iteration space partitioning goes in ENTRY_BB. */
4214e4b17023SJohn Marino gsi = gsi_last_bb (entry_bb);
4215e4b17023SJohn Marino gcc_assert (gimple_code (gsi_stmt (gsi)) == GIMPLE_OMP_FOR);
4216e4b17023SJohn Marino
4217e4b17023SJohn Marino t = build_call_expr (builtin_decl_explicit (BUILT_IN_OMP_GET_NUM_THREADS), 0);
4218e4b17023SJohn Marino t = fold_convert (itype, t);
4219e4b17023SJohn Marino nthreads = force_gimple_operand_gsi (&gsi, t, true, NULL_TREE,
4220e4b17023SJohn Marino true, GSI_SAME_STMT);
4221e4b17023SJohn Marino
4222e4b17023SJohn Marino t = build_call_expr (builtin_decl_explicit (BUILT_IN_OMP_GET_THREAD_NUM), 0);
4223e4b17023SJohn Marino t = fold_convert (itype, t);
4224e4b17023SJohn Marino threadid = force_gimple_operand_gsi (&gsi, t, true, NULL_TREE,
4225e4b17023SJohn Marino true, GSI_SAME_STMT);
4226e4b17023SJohn Marino
4227e4b17023SJohn Marino fd->loop.n1
4228e4b17023SJohn Marino = force_gimple_operand_gsi (&gsi, fold_convert (type, fd->loop.n1),
4229e4b17023SJohn Marino true, NULL_TREE, true, GSI_SAME_STMT);
4230e4b17023SJohn Marino fd->loop.n2
4231e4b17023SJohn Marino = force_gimple_operand_gsi (&gsi, fold_convert (itype, fd->loop.n2),
4232e4b17023SJohn Marino true, NULL_TREE, true, GSI_SAME_STMT);
4233e4b17023SJohn Marino fd->loop.step
4234e4b17023SJohn Marino = force_gimple_operand_gsi (&gsi, fold_convert (itype, fd->loop.step),
4235e4b17023SJohn Marino true, NULL_TREE, true, GSI_SAME_STMT);
4236e4b17023SJohn Marino
4237e4b17023SJohn Marino t = build_int_cst (itype, (fd->loop.cond_code == LT_EXPR ? -1 : 1));
4238e4b17023SJohn Marino t = fold_build2 (PLUS_EXPR, itype, fd->loop.step, t);
4239e4b17023SJohn Marino t = fold_build2 (PLUS_EXPR, itype, t, fd->loop.n2);
4240e4b17023SJohn Marino t = fold_build2 (MINUS_EXPR, itype, t, fold_convert (itype, fd->loop.n1));
4241e4b17023SJohn Marino if (TYPE_UNSIGNED (itype) && fd->loop.cond_code == GT_EXPR)
4242e4b17023SJohn Marino t = fold_build2 (TRUNC_DIV_EXPR, itype,
4243e4b17023SJohn Marino fold_build1 (NEGATE_EXPR, itype, t),
4244e4b17023SJohn Marino fold_build1 (NEGATE_EXPR, itype, fd->loop.step));
4245e4b17023SJohn Marino else
4246e4b17023SJohn Marino t = fold_build2 (TRUNC_DIV_EXPR, itype, t, fd->loop.step);
4247e4b17023SJohn Marino t = fold_convert (itype, t);
4248e4b17023SJohn Marino n = force_gimple_operand_gsi (&gsi, t, true, NULL_TREE, true, GSI_SAME_STMT);
4249e4b17023SJohn Marino
4250e4b17023SJohn Marino q = create_tmp_var (itype, "q");
4251e4b17023SJohn Marino t = fold_build2 (TRUNC_DIV_EXPR, itype, n, nthreads);
4252e4b17023SJohn Marino t = force_gimple_operand_gsi (&gsi, t, false, NULL_TREE, true, GSI_SAME_STMT);
4253e4b17023SJohn Marino gsi_insert_before (&gsi, gimple_build_assign (q, t), GSI_SAME_STMT);
4254e4b17023SJohn Marino
4255e4b17023SJohn Marino tt = create_tmp_var (itype, "tt");
4256e4b17023SJohn Marino t = fold_build2 (TRUNC_MOD_EXPR, itype, n, nthreads);
4257e4b17023SJohn Marino t = force_gimple_operand_gsi (&gsi, t, false, NULL_TREE, true, GSI_SAME_STMT);
4258e4b17023SJohn Marino gsi_insert_before (&gsi, gimple_build_assign (tt, t), GSI_SAME_STMT);
4259e4b17023SJohn Marino
4260e4b17023SJohn Marino t = build2 (LT_EXPR, boolean_type_node, threadid, tt);
4261e4b17023SJohn Marino stmt = gimple_build_cond_empty (t);
4262e4b17023SJohn Marino gsi_insert_before (&gsi, stmt, GSI_SAME_STMT);
4263e4b17023SJohn Marino
4264e4b17023SJohn Marino second_bb = split_block (entry_bb, stmt)->dest;
4265e4b17023SJohn Marino gsi = gsi_last_bb (second_bb);
4266e4b17023SJohn Marino gcc_assert (gimple_code (gsi_stmt (gsi)) == GIMPLE_OMP_FOR);
4267e4b17023SJohn Marino
4268e4b17023SJohn Marino gsi_insert_before (&gsi, gimple_build_assign (tt, build_int_cst (itype, 0)),
4269e4b17023SJohn Marino GSI_SAME_STMT);
4270e4b17023SJohn Marino stmt = gimple_build_assign_with_ops (PLUS_EXPR, q, q,
4271e4b17023SJohn Marino build_int_cst (itype, 1));
4272e4b17023SJohn Marino gsi_insert_before (&gsi, stmt, GSI_SAME_STMT);
4273e4b17023SJohn Marino
4274e4b17023SJohn Marino third_bb = split_block (second_bb, stmt)->dest;
4275e4b17023SJohn Marino gsi = gsi_last_bb (third_bb);
4276e4b17023SJohn Marino gcc_assert (gimple_code (gsi_stmt (gsi)) == GIMPLE_OMP_FOR);
4277e4b17023SJohn Marino
4278e4b17023SJohn Marino t = build2 (MULT_EXPR, itype, q, threadid);
4279e4b17023SJohn Marino t = build2 (PLUS_EXPR, itype, t, tt);
4280e4b17023SJohn Marino s0 = force_gimple_operand_gsi (&gsi, t, true, NULL_TREE, true, GSI_SAME_STMT);
4281e4b17023SJohn Marino
4282e4b17023SJohn Marino t = fold_build2 (PLUS_EXPR, itype, s0, q);
4283e4b17023SJohn Marino e0 = force_gimple_operand_gsi (&gsi, t, true, NULL_TREE, true, GSI_SAME_STMT);
4284e4b17023SJohn Marino
4285e4b17023SJohn Marino t = build2 (GE_EXPR, boolean_type_node, s0, e0);
4286e4b17023SJohn Marino gsi_insert_before (&gsi, gimple_build_cond_empty (t), GSI_SAME_STMT);
4287e4b17023SJohn Marino
4288e4b17023SJohn Marino /* Remove the GIMPLE_OMP_FOR statement. */
4289e4b17023SJohn Marino gsi_remove (&gsi, true);
4290e4b17023SJohn Marino
4291e4b17023SJohn Marino /* Setup code for sequential iteration goes in SEQ_START_BB. */
4292e4b17023SJohn Marino gsi = gsi_start_bb (seq_start_bb);
4293e4b17023SJohn Marino
4294e4b17023SJohn Marino t = fold_convert (itype, s0);
4295e4b17023SJohn Marino t = fold_build2 (MULT_EXPR, itype, t, fd->loop.step);
4296e4b17023SJohn Marino if (POINTER_TYPE_P (type))
4297e4b17023SJohn Marino t = fold_build_pointer_plus (fd->loop.n1, t);
4298e4b17023SJohn Marino else
4299e4b17023SJohn Marino t = fold_build2 (PLUS_EXPR, type, t, fd->loop.n1);
4300e4b17023SJohn Marino t = force_gimple_operand_gsi (&gsi, t, false, NULL_TREE,
4301e4b17023SJohn Marino false, GSI_CONTINUE_LINKING);
4302e4b17023SJohn Marino stmt = gimple_build_assign (fd->loop.v, t);
4303e4b17023SJohn Marino gsi_insert_after (&gsi, stmt, GSI_CONTINUE_LINKING);
4304e4b17023SJohn Marino
4305e4b17023SJohn Marino t = fold_convert (itype, e0);
4306e4b17023SJohn Marino t = fold_build2 (MULT_EXPR, itype, t, fd->loop.step);
4307e4b17023SJohn Marino if (POINTER_TYPE_P (type))
4308e4b17023SJohn Marino t = fold_build_pointer_plus (fd->loop.n1, t);
4309e4b17023SJohn Marino else
4310e4b17023SJohn Marino t = fold_build2 (PLUS_EXPR, type, t, fd->loop.n1);
4311e4b17023SJohn Marino e = force_gimple_operand_gsi (&gsi, t, true, NULL_TREE,
4312e4b17023SJohn Marino false, GSI_CONTINUE_LINKING);
4313e4b17023SJohn Marino
4314e4b17023SJohn Marino /* The code controlling the sequential loop replaces the
4315e4b17023SJohn Marino GIMPLE_OMP_CONTINUE. */
4316e4b17023SJohn Marino gsi = gsi_last_bb (cont_bb);
4317e4b17023SJohn Marino stmt = gsi_stmt (gsi);
4318e4b17023SJohn Marino gcc_assert (gimple_code (stmt) == GIMPLE_OMP_CONTINUE);
4319e4b17023SJohn Marino vmain = gimple_omp_continue_control_use (stmt);
4320e4b17023SJohn Marino vback = gimple_omp_continue_control_def (stmt);
4321e4b17023SJohn Marino
4322e4b17023SJohn Marino if (POINTER_TYPE_P (type))
4323e4b17023SJohn Marino t = fold_build_pointer_plus (vmain, fd->loop.step);
4324e4b17023SJohn Marino else
4325e4b17023SJohn Marino t = fold_build2 (PLUS_EXPR, type, vmain, fd->loop.step);
4326e4b17023SJohn Marino t = force_gimple_operand_gsi (&gsi, t, false, NULL_TREE,
4327e4b17023SJohn Marino true, GSI_SAME_STMT);
4328e4b17023SJohn Marino stmt = gimple_build_assign (vback, t);
4329e4b17023SJohn Marino gsi_insert_before (&gsi, stmt, GSI_SAME_STMT);
4330e4b17023SJohn Marino
4331e4b17023SJohn Marino t = build2 (fd->loop.cond_code, boolean_type_node, vback, e);
4332e4b17023SJohn Marino gsi_insert_before (&gsi, gimple_build_cond_empty (t), GSI_SAME_STMT);
4333e4b17023SJohn Marino
4334e4b17023SJohn Marino /* Remove the GIMPLE_OMP_CONTINUE statement. */
4335e4b17023SJohn Marino gsi_remove (&gsi, true);
4336e4b17023SJohn Marino
4337e4b17023SJohn Marino /* Replace the GIMPLE_OMP_RETURN with a barrier, or nothing. */
4338e4b17023SJohn Marino gsi = gsi_last_bb (exit_bb);
4339e4b17023SJohn Marino if (!gimple_omp_return_nowait_p (gsi_stmt (gsi)))
4340e4b17023SJohn Marino force_gimple_operand_gsi (&gsi, build_omp_barrier (), false, NULL_TREE,
4341e4b17023SJohn Marino false, GSI_SAME_STMT);
4342e4b17023SJohn Marino gsi_remove (&gsi, true);
4343e4b17023SJohn Marino
4344e4b17023SJohn Marino /* Connect all the blocks. */
4345e4b17023SJohn Marino ep = make_edge (entry_bb, third_bb, EDGE_FALSE_VALUE);
4346e4b17023SJohn Marino ep->probability = REG_BR_PROB_BASE / 4 * 3;
4347e4b17023SJohn Marino ep = find_edge (entry_bb, second_bb);
4348e4b17023SJohn Marino ep->flags = EDGE_TRUE_VALUE;
4349e4b17023SJohn Marino ep->probability = REG_BR_PROB_BASE / 4;
4350e4b17023SJohn Marino find_edge (third_bb, seq_start_bb)->flags = EDGE_FALSE_VALUE;
4351e4b17023SJohn Marino find_edge (third_bb, fin_bb)->flags = EDGE_TRUE_VALUE;
4352e4b17023SJohn Marino
4353e4b17023SJohn Marino find_edge (cont_bb, body_bb)->flags = EDGE_TRUE_VALUE;
4354e4b17023SJohn Marino find_edge (cont_bb, fin_bb)->flags = EDGE_FALSE_VALUE;
4355e4b17023SJohn Marino
4356e4b17023SJohn Marino set_immediate_dominator (CDI_DOMINATORS, second_bb, entry_bb);
4357e4b17023SJohn Marino set_immediate_dominator (CDI_DOMINATORS, third_bb, entry_bb);
4358e4b17023SJohn Marino set_immediate_dominator (CDI_DOMINATORS, seq_start_bb, third_bb);
4359e4b17023SJohn Marino set_immediate_dominator (CDI_DOMINATORS, body_bb,
4360e4b17023SJohn Marino recompute_dominator (CDI_DOMINATORS, body_bb));
4361e4b17023SJohn Marino set_immediate_dominator (CDI_DOMINATORS, fin_bb,
4362e4b17023SJohn Marino recompute_dominator (CDI_DOMINATORS, fin_bb));
4363e4b17023SJohn Marino }
4364e4b17023SJohn Marino
4365e4b17023SJohn Marino
4366e4b17023SJohn Marino /* A subroutine of expand_omp_for. Generate code for a parallel
4367e4b17023SJohn Marino loop with static schedule and a specified chunk size. Given
4368e4b17023SJohn Marino parameters:
4369e4b17023SJohn Marino
4370e4b17023SJohn Marino for (V = N1; V cond N2; V += STEP) BODY;
4371e4b17023SJohn Marino
4372e4b17023SJohn Marino where COND is "<" or ">", we generate pseudocode
4373e4b17023SJohn Marino
4374e4b17023SJohn Marino if (cond is <)
4375e4b17023SJohn Marino adj = STEP - 1;
4376e4b17023SJohn Marino else
4377e4b17023SJohn Marino adj = STEP + 1;
4378e4b17023SJohn Marino if ((__typeof (V)) -1 > 0 && cond is >)
4379e4b17023SJohn Marino n = -(adj + N2 - N1) / -STEP;
4380e4b17023SJohn Marino else
4381e4b17023SJohn Marino n = (adj + N2 - N1) / STEP;
4382e4b17023SJohn Marino trip = 0;
4383e4b17023SJohn Marino V = threadid * CHUNK * STEP + N1; -- this extra definition of V is
4384e4b17023SJohn Marino here so that V is defined
4385e4b17023SJohn Marino if the loop is not entered
4386e4b17023SJohn Marino L0:
4387e4b17023SJohn Marino s0 = (trip * nthreads + threadid) * CHUNK;
4388e4b17023SJohn Marino e0 = min(s0 + CHUNK, n);
4389e4b17023SJohn Marino if (s0 < n) goto L1; else goto L4;
4390e4b17023SJohn Marino L1:
4391e4b17023SJohn Marino V = s0 * STEP + N1;
4392e4b17023SJohn Marino e = e0 * STEP + N1;
4393e4b17023SJohn Marino L2:
4394e4b17023SJohn Marino BODY;
4395e4b17023SJohn Marino V += STEP;
4396e4b17023SJohn Marino if (V cond e) goto L2; else goto L3;
4397e4b17023SJohn Marino L3:
4398e4b17023SJohn Marino trip += 1;
4399e4b17023SJohn Marino goto L0;
4400e4b17023SJohn Marino L4:
4401e4b17023SJohn Marino */
4402e4b17023SJohn Marino
4403e4b17023SJohn Marino static void
expand_omp_for_static_chunk(struct omp_region * region,struct omp_for_data * fd)4404e4b17023SJohn Marino expand_omp_for_static_chunk (struct omp_region *region, struct omp_for_data *fd)
4405e4b17023SJohn Marino {
4406e4b17023SJohn Marino tree n, s0, e0, e, t;
4407e4b17023SJohn Marino tree trip_var, trip_init, trip_main, trip_back, nthreads, threadid;
4408e4b17023SJohn Marino tree type, itype, v_main, v_back, v_extra;
4409e4b17023SJohn Marino basic_block entry_bb, exit_bb, body_bb, seq_start_bb, iter_part_bb;
4410e4b17023SJohn Marino basic_block trip_update_bb, cont_bb, fin_bb;
4411e4b17023SJohn Marino gimple_stmt_iterator si;
4412e4b17023SJohn Marino gimple stmt;
4413e4b17023SJohn Marino edge se;
4414e4b17023SJohn Marino
4415e4b17023SJohn Marino itype = type = TREE_TYPE (fd->loop.v);
4416e4b17023SJohn Marino if (POINTER_TYPE_P (type))
4417e4b17023SJohn Marino itype = lang_hooks.types.type_for_size (TYPE_PRECISION (type), 0);
4418e4b17023SJohn Marino
4419e4b17023SJohn Marino entry_bb = region->entry;
4420e4b17023SJohn Marino se = split_block (entry_bb, last_stmt (entry_bb));
4421e4b17023SJohn Marino entry_bb = se->src;
4422e4b17023SJohn Marino iter_part_bb = se->dest;
4423e4b17023SJohn Marino cont_bb = region->cont;
4424e4b17023SJohn Marino gcc_assert (EDGE_COUNT (iter_part_bb->succs) == 2);
4425e4b17023SJohn Marino gcc_assert (BRANCH_EDGE (iter_part_bb)->dest
4426e4b17023SJohn Marino == FALLTHRU_EDGE (cont_bb)->dest);
4427e4b17023SJohn Marino seq_start_bb = split_edge (FALLTHRU_EDGE (iter_part_bb));
4428e4b17023SJohn Marino body_bb = single_succ (seq_start_bb);
4429e4b17023SJohn Marino gcc_assert (BRANCH_EDGE (cont_bb)->dest == body_bb);
4430e4b17023SJohn Marino gcc_assert (EDGE_COUNT (cont_bb->succs) == 2);
4431e4b17023SJohn Marino fin_bb = FALLTHRU_EDGE (cont_bb)->dest;
4432e4b17023SJohn Marino trip_update_bb = split_edge (FALLTHRU_EDGE (cont_bb));
4433e4b17023SJohn Marino exit_bb = region->exit;
4434e4b17023SJohn Marino
4435e4b17023SJohn Marino /* Trip and adjustment setup goes in ENTRY_BB. */
4436e4b17023SJohn Marino si = gsi_last_bb (entry_bb);
4437e4b17023SJohn Marino gcc_assert (gimple_code (gsi_stmt (si)) == GIMPLE_OMP_FOR);
4438e4b17023SJohn Marino
4439e4b17023SJohn Marino t = build_call_expr (builtin_decl_explicit (BUILT_IN_OMP_GET_NUM_THREADS), 0);
4440e4b17023SJohn Marino t = fold_convert (itype, t);
4441e4b17023SJohn Marino nthreads = force_gimple_operand_gsi (&si, t, true, NULL_TREE,
4442e4b17023SJohn Marino true, GSI_SAME_STMT);
4443e4b17023SJohn Marino
4444e4b17023SJohn Marino t = build_call_expr (builtin_decl_explicit (BUILT_IN_OMP_GET_THREAD_NUM), 0);
4445e4b17023SJohn Marino t = fold_convert (itype, t);
4446e4b17023SJohn Marino threadid = force_gimple_operand_gsi (&si, t, true, NULL_TREE,
4447e4b17023SJohn Marino true, GSI_SAME_STMT);
4448e4b17023SJohn Marino
4449e4b17023SJohn Marino fd->loop.n1
4450e4b17023SJohn Marino = force_gimple_operand_gsi (&si, fold_convert (type, fd->loop.n1),
4451e4b17023SJohn Marino true, NULL_TREE, true, GSI_SAME_STMT);
4452e4b17023SJohn Marino fd->loop.n2
4453e4b17023SJohn Marino = force_gimple_operand_gsi (&si, fold_convert (itype, fd->loop.n2),
4454e4b17023SJohn Marino true, NULL_TREE, true, GSI_SAME_STMT);
4455e4b17023SJohn Marino fd->loop.step
4456e4b17023SJohn Marino = force_gimple_operand_gsi (&si, fold_convert (itype, fd->loop.step),
4457e4b17023SJohn Marino true, NULL_TREE, true, GSI_SAME_STMT);
4458e4b17023SJohn Marino fd->chunk_size
4459e4b17023SJohn Marino = force_gimple_operand_gsi (&si, fold_convert (itype, fd->chunk_size),
4460e4b17023SJohn Marino true, NULL_TREE, true, GSI_SAME_STMT);
4461e4b17023SJohn Marino
4462e4b17023SJohn Marino t = build_int_cst (itype, (fd->loop.cond_code == LT_EXPR ? -1 : 1));
4463e4b17023SJohn Marino t = fold_build2 (PLUS_EXPR, itype, fd->loop.step, t);
4464e4b17023SJohn Marino t = fold_build2 (PLUS_EXPR, itype, t, fd->loop.n2);
4465e4b17023SJohn Marino t = fold_build2 (MINUS_EXPR, itype, t, fold_convert (itype, fd->loop.n1));
4466e4b17023SJohn Marino if (TYPE_UNSIGNED (itype) && fd->loop.cond_code == GT_EXPR)
4467e4b17023SJohn Marino t = fold_build2 (TRUNC_DIV_EXPR, itype,
4468e4b17023SJohn Marino fold_build1 (NEGATE_EXPR, itype, t),
4469e4b17023SJohn Marino fold_build1 (NEGATE_EXPR, itype, fd->loop.step));
4470e4b17023SJohn Marino else
4471e4b17023SJohn Marino t = fold_build2 (TRUNC_DIV_EXPR, itype, t, fd->loop.step);
4472e4b17023SJohn Marino t = fold_convert (itype, t);
4473e4b17023SJohn Marino n = force_gimple_operand_gsi (&si, t, true, NULL_TREE,
4474e4b17023SJohn Marino true, GSI_SAME_STMT);
4475e4b17023SJohn Marino
4476e4b17023SJohn Marino trip_var = create_tmp_var (itype, ".trip");
4477e4b17023SJohn Marino if (gimple_in_ssa_p (cfun))
4478e4b17023SJohn Marino {
4479e4b17023SJohn Marino add_referenced_var (trip_var);
4480e4b17023SJohn Marino trip_init = make_ssa_name (trip_var, NULL);
4481e4b17023SJohn Marino trip_main = make_ssa_name (trip_var, NULL);
4482e4b17023SJohn Marino trip_back = make_ssa_name (trip_var, NULL);
4483e4b17023SJohn Marino }
4484e4b17023SJohn Marino else
4485e4b17023SJohn Marino {
4486e4b17023SJohn Marino trip_init = trip_var;
4487e4b17023SJohn Marino trip_main = trip_var;
4488e4b17023SJohn Marino trip_back = trip_var;
4489e4b17023SJohn Marino }
4490e4b17023SJohn Marino
4491e4b17023SJohn Marino stmt = gimple_build_assign (trip_init, build_int_cst (itype, 0));
4492e4b17023SJohn Marino gsi_insert_before (&si, stmt, GSI_SAME_STMT);
4493e4b17023SJohn Marino
4494e4b17023SJohn Marino t = fold_build2 (MULT_EXPR, itype, threadid, fd->chunk_size);
4495e4b17023SJohn Marino t = fold_build2 (MULT_EXPR, itype, t, fd->loop.step);
4496e4b17023SJohn Marino if (POINTER_TYPE_P (type))
4497e4b17023SJohn Marino t = fold_build_pointer_plus (fd->loop.n1, t);
4498e4b17023SJohn Marino else
4499e4b17023SJohn Marino t = fold_build2 (PLUS_EXPR, type, t, fd->loop.n1);
4500e4b17023SJohn Marino v_extra = force_gimple_operand_gsi (&si, t, true, NULL_TREE,
4501e4b17023SJohn Marino true, GSI_SAME_STMT);
4502e4b17023SJohn Marino
4503e4b17023SJohn Marino /* Remove the GIMPLE_OMP_FOR. */
4504e4b17023SJohn Marino gsi_remove (&si, true);
4505e4b17023SJohn Marino
4506e4b17023SJohn Marino /* Iteration space partitioning goes in ITER_PART_BB. */
4507e4b17023SJohn Marino si = gsi_last_bb (iter_part_bb);
4508e4b17023SJohn Marino
4509e4b17023SJohn Marino t = fold_build2 (MULT_EXPR, itype, trip_main, nthreads);
4510e4b17023SJohn Marino t = fold_build2 (PLUS_EXPR, itype, t, threadid);
4511e4b17023SJohn Marino t = fold_build2 (MULT_EXPR, itype, t, fd->chunk_size);
4512e4b17023SJohn Marino s0 = force_gimple_operand_gsi (&si, t, true, NULL_TREE,
4513e4b17023SJohn Marino false, GSI_CONTINUE_LINKING);
4514e4b17023SJohn Marino
4515e4b17023SJohn Marino t = fold_build2 (PLUS_EXPR, itype, s0, fd->chunk_size);
4516e4b17023SJohn Marino t = fold_build2 (MIN_EXPR, itype, t, n);
4517e4b17023SJohn Marino e0 = force_gimple_operand_gsi (&si, t, true, NULL_TREE,
4518e4b17023SJohn Marino false, GSI_CONTINUE_LINKING);
4519e4b17023SJohn Marino
4520e4b17023SJohn Marino t = build2 (LT_EXPR, boolean_type_node, s0, n);
4521e4b17023SJohn Marino gsi_insert_after (&si, gimple_build_cond_empty (t), GSI_CONTINUE_LINKING);
4522e4b17023SJohn Marino
4523e4b17023SJohn Marino /* Setup code for sequential iteration goes in SEQ_START_BB. */
4524e4b17023SJohn Marino si = gsi_start_bb (seq_start_bb);
4525e4b17023SJohn Marino
4526e4b17023SJohn Marino t = fold_convert (itype, s0);
4527e4b17023SJohn Marino t = fold_build2 (MULT_EXPR, itype, t, fd->loop.step);
4528e4b17023SJohn Marino if (POINTER_TYPE_P (type))
4529e4b17023SJohn Marino t = fold_build_pointer_plus (fd->loop.n1, t);
4530e4b17023SJohn Marino else
4531e4b17023SJohn Marino t = fold_build2 (PLUS_EXPR, type, t, fd->loop.n1);
4532e4b17023SJohn Marino t = force_gimple_operand_gsi (&si, t, false, NULL_TREE,
4533e4b17023SJohn Marino false, GSI_CONTINUE_LINKING);
4534e4b17023SJohn Marino stmt = gimple_build_assign (fd->loop.v, t);
4535e4b17023SJohn Marino gsi_insert_after (&si, stmt, GSI_CONTINUE_LINKING);
4536e4b17023SJohn Marino
4537e4b17023SJohn Marino t = fold_convert (itype, e0);
4538e4b17023SJohn Marino t = fold_build2 (MULT_EXPR, itype, t, fd->loop.step);
4539e4b17023SJohn Marino if (POINTER_TYPE_P (type))
4540e4b17023SJohn Marino t = fold_build_pointer_plus (fd->loop.n1, t);
4541e4b17023SJohn Marino else
4542e4b17023SJohn Marino t = fold_build2 (PLUS_EXPR, type, t, fd->loop.n1);
4543e4b17023SJohn Marino e = force_gimple_operand_gsi (&si, t, true, NULL_TREE,
4544e4b17023SJohn Marino false, GSI_CONTINUE_LINKING);
4545e4b17023SJohn Marino
4546e4b17023SJohn Marino /* The code controlling the sequential loop goes in CONT_BB,
4547e4b17023SJohn Marino replacing the GIMPLE_OMP_CONTINUE. */
4548e4b17023SJohn Marino si = gsi_last_bb (cont_bb);
4549e4b17023SJohn Marino stmt = gsi_stmt (si);
4550e4b17023SJohn Marino gcc_assert (gimple_code (stmt) == GIMPLE_OMP_CONTINUE);
4551e4b17023SJohn Marino v_main = gimple_omp_continue_control_use (stmt);
4552e4b17023SJohn Marino v_back = gimple_omp_continue_control_def (stmt);
4553e4b17023SJohn Marino
4554e4b17023SJohn Marino if (POINTER_TYPE_P (type))
4555e4b17023SJohn Marino t = fold_build_pointer_plus (v_main, fd->loop.step);
4556e4b17023SJohn Marino else
4557e4b17023SJohn Marino t = fold_build2 (PLUS_EXPR, type, v_main, fd->loop.step);
4558e4b17023SJohn Marino stmt = gimple_build_assign (v_back, t);
4559e4b17023SJohn Marino gsi_insert_before (&si, stmt, GSI_SAME_STMT);
4560e4b17023SJohn Marino
4561e4b17023SJohn Marino t = build2 (fd->loop.cond_code, boolean_type_node, v_back, e);
4562e4b17023SJohn Marino gsi_insert_before (&si, gimple_build_cond_empty (t), GSI_SAME_STMT);
4563e4b17023SJohn Marino
4564e4b17023SJohn Marino /* Remove GIMPLE_OMP_CONTINUE. */
4565e4b17023SJohn Marino gsi_remove (&si, true);
4566e4b17023SJohn Marino
4567e4b17023SJohn Marino /* Trip update code goes into TRIP_UPDATE_BB. */
4568e4b17023SJohn Marino si = gsi_start_bb (trip_update_bb);
4569e4b17023SJohn Marino
4570e4b17023SJohn Marino t = build_int_cst (itype, 1);
4571e4b17023SJohn Marino t = build2 (PLUS_EXPR, itype, trip_main, t);
4572e4b17023SJohn Marino stmt = gimple_build_assign (trip_back, t);
4573e4b17023SJohn Marino gsi_insert_after (&si, stmt, GSI_CONTINUE_LINKING);
4574e4b17023SJohn Marino
4575e4b17023SJohn Marino /* Replace the GIMPLE_OMP_RETURN with a barrier, or nothing. */
4576e4b17023SJohn Marino si = gsi_last_bb (exit_bb);
4577e4b17023SJohn Marino if (!gimple_omp_return_nowait_p (gsi_stmt (si)))
4578e4b17023SJohn Marino force_gimple_operand_gsi (&si, build_omp_barrier (), false, NULL_TREE,
4579e4b17023SJohn Marino false, GSI_SAME_STMT);
4580e4b17023SJohn Marino gsi_remove (&si, true);
4581e4b17023SJohn Marino
4582e4b17023SJohn Marino /* Connect the new blocks. */
4583e4b17023SJohn Marino find_edge (iter_part_bb, seq_start_bb)->flags = EDGE_TRUE_VALUE;
4584e4b17023SJohn Marino find_edge (iter_part_bb, fin_bb)->flags = EDGE_FALSE_VALUE;
4585e4b17023SJohn Marino
4586e4b17023SJohn Marino find_edge (cont_bb, body_bb)->flags = EDGE_TRUE_VALUE;
4587e4b17023SJohn Marino find_edge (cont_bb, trip_update_bb)->flags = EDGE_FALSE_VALUE;
4588e4b17023SJohn Marino
4589e4b17023SJohn Marino redirect_edge_and_branch (single_succ_edge (trip_update_bb), iter_part_bb);
4590e4b17023SJohn Marino
4591e4b17023SJohn Marino if (gimple_in_ssa_p (cfun))
4592e4b17023SJohn Marino {
4593e4b17023SJohn Marino gimple_stmt_iterator psi;
4594e4b17023SJohn Marino gimple phi;
4595e4b17023SJohn Marino edge re, ene;
4596e4b17023SJohn Marino edge_var_map_vector head;
4597e4b17023SJohn Marino edge_var_map *vm;
4598e4b17023SJohn Marino size_t i;
4599e4b17023SJohn Marino
4600e4b17023SJohn Marino /* When we redirect the edge from trip_update_bb to iter_part_bb, we
4601e4b17023SJohn Marino remove arguments of the phi nodes in fin_bb. We need to create
4602e4b17023SJohn Marino appropriate phi nodes in iter_part_bb instead. */
4603e4b17023SJohn Marino se = single_pred_edge (fin_bb);
4604e4b17023SJohn Marino re = single_succ_edge (trip_update_bb);
4605e4b17023SJohn Marino head = redirect_edge_var_map_vector (re);
4606e4b17023SJohn Marino ene = single_succ_edge (entry_bb);
4607e4b17023SJohn Marino
4608e4b17023SJohn Marino psi = gsi_start_phis (fin_bb);
4609e4b17023SJohn Marino for (i = 0; !gsi_end_p (psi) && VEC_iterate (edge_var_map, head, i, vm);
4610e4b17023SJohn Marino gsi_next (&psi), ++i)
4611e4b17023SJohn Marino {
4612e4b17023SJohn Marino gimple nphi;
4613e4b17023SJohn Marino source_location locus;
4614e4b17023SJohn Marino
4615e4b17023SJohn Marino phi = gsi_stmt (psi);
4616e4b17023SJohn Marino t = gimple_phi_result (phi);
4617e4b17023SJohn Marino gcc_assert (t == redirect_edge_var_map_result (vm));
4618e4b17023SJohn Marino nphi = create_phi_node (t, iter_part_bb);
4619e4b17023SJohn Marino SSA_NAME_DEF_STMT (t) = nphi;
4620e4b17023SJohn Marino
4621e4b17023SJohn Marino t = PHI_ARG_DEF_FROM_EDGE (phi, se);
4622e4b17023SJohn Marino locus = gimple_phi_arg_location_from_edge (phi, se);
4623e4b17023SJohn Marino
4624e4b17023SJohn Marino /* A special case -- fd->loop.v is not yet computed in
4625e4b17023SJohn Marino iter_part_bb, we need to use v_extra instead. */
4626e4b17023SJohn Marino if (t == fd->loop.v)
4627e4b17023SJohn Marino t = v_extra;
4628e4b17023SJohn Marino add_phi_arg (nphi, t, ene, locus);
4629e4b17023SJohn Marino locus = redirect_edge_var_map_location (vm);
4630e4b17023SJohn Marino add_phi_arg (nphi, redirect_edge_var_map_def (vm), re, locus);
4631e4b17023SJohn Marino }
4632e4b17023SJohn Marino gcc_assert (!gsi_end_p (psi) && i == VEC_length (edge_var_map, head));
4633e4b17023SJohn Marino redirect_edge_var_map_clear (re);
4634e4b17023SJohn Marino while (1)
4635e4b17023SJohn Marino {
4636e4b17023SJohn Marino psi = gsi_start_phis (fin_bb);
4637e4b17023SJohn Marino if (gsi_end_p (psi))
4638e4b17023SJohn Marino break;
4639e4b17023SJohn Marino remove_phi_node (&psi, false);
4640e4b17023SJohn Marino }
4641e4b17023SJohn Marino
4642e4b17023SJohn Marino /* Make phi node for trip. */
4643e4b17023SJohn Marino phi = create_phi_node (trip_main, iter_part_bb);
4644e4b17023SJohn Marino SSA_NAME_DEF_STMT (trip_main) = phi;
4645e4b17023SJohn Marino add_phi_arg (phi, trip_back, single_succ_edge (trip_update_bb),
4646e4b17023SJohn Marino UNKNOWN_LOCATION);
4647e4b17023SJohn Marino add_phi_arg (phi, trip_init, single_succ_edge (entry_bb),
4648e4b17023SJohn Marino UNKNOWN_LOCATION);
4649e4b17023SJohn Marino }
4650e4b17023SJohn Marino
4651e4b17023SJohn Marino set_immediate_dominator (CDI_DOMINATORS, trip_update_bb, cont_bb);
4652e4b17023SJohn Marino set_immediate_dominator (CDI_DOMINATORS, iter_part_bb,
4653e4b17023SJohn Marino recompute_dominator (CDI_DOMINATORS, iter_part_bb));
4654e4b17023SJohn Marino set_immediate_dominator (CDI_DOMINATORS, fin_bb,
4655e4b17023SJohn Marino recompute_dominator (CDI_DOMINATORS, fin_bb));
4656e4b17023SJohn Marino set_immediate_dominator (CDI_DOMINATORS, seq_start_bb,
4657e4b17023SJohn Marino recompute_dominator (CDI_DOMINATORS, seq_start_bb));
4658e4b17023SJohn Marino set_immediate_dominator (CDI_DOMINATORS, body_bb,
4659e4b17023SJohn Marino recompute_dominator (CDI_DOMINATORS, body_bb));
4660e4b17023SJohn Marino }
4661e4b17023SJohn Marino
4662e4b17023SJohn Marino
4663e4b17023SJohn Marino /* Expand the OpenMP loop defined by REGION. */
4664e4b17023SJohn Marino
4665e4b17023SJohn Marino static void
expand_omp_for(struct omp_region * region)4666e4b17023SJohn Marino expand_omp_for (struct omp_region *region)
4667e4b17023SJohn Marino {
4668e4b17023SJohn Marino struct omp_for_data fd;
4669e4b17023SJohn Marino struct omp_for_data_loop *loops;
4670e4b17023SJohn Marino
4671e4b17023SJohn Marino loops
4672e4b17023SJohn Marino = (struct omp_for_data_loop *)
4673e4b17023SJohn Marino alloca (gimple_omp_for_collapse (last_stmt (region->entry))
4674e4b17023SJohn Marino * sizeof (struct omp_for_data_loop));
4675e4b17023SJohn Marino extract_omp_for_data (last_stmt (region->entry), &fd, loops);
4676e4b17023SJohn Marino region->sched_kind = fd.sched_kind;
4677e4b17023SJohn Marino
4678e4b17023SJohn Marino gcc_assert (EDGE_COUNT (region->entry->succs) == 2);
4679e4b17023SJohn Marino BRANCH_EDGE (region->entry)->flags &= ~EDGE_ABNORMAL;
4680e4b17023SJohn Marino FALLTHRU_EDGE (region->entry)->flags &= ~EDGE_ABNORMAL;
4681e4b17023SJohn Marino if (region->cont)
4682e4b17023SJohn Marino {
4683e4b17023SJohn Marino gcc_assert (EDGE_COUNT (region->cont->succs) == 2);
4684e4b17023SJohn Marino BRANCH_EDGE (region->cont)->flags &= ~EDGE_ABNORMAL;
4685e4b17023SJohn Marino FALLTHRU_EDGE (region->cont)->flags &= ~EDGE_ABNORMAL;
4686e4b17023SJohn Marino }
4687e4b17023SJohn Marino
4688e4b17023SJohn Marino if (fd.sched_kind == OMP_CLAUSE_SCHEDULE_STATIC
4689e4b17023SJohn Marino && !fd.have_ordered
4690e4b17023SJohn Marino && fd.collapse == 1
4691e4b17023SJohn Marino && region->cont != NULL)
4692e4b17023SJohn Marino {
4693e4b17023SJohn Marino if (fd.chunk_size == NULL)
4694e4b17023SJohn Marino expand_omp_for_static_nochunk (region, &fd);
4695e4b17023SJohn Marino else
4696e4b17023SJohn Marino expand_omp_for_static_chunk (region, &fd);
4697e4b17023SJohn Marino }
4698e4b17023SJohn Marino else
4699e4b17023SJohn Marino {
4700e4b17023SJohn Marino int fn_index, start_ix, next_ix;
4701e4b17023SJohn Marino
4702e4b17023SJohn Marino if (fd.chunk_size == NULL
4703e4b17023SJohn Marino && fd.sched_kind == OMP_CLAUSE_SCHEDULE_STATIC)
4704e4b17023SJohn Marino fd.chunk_size = integer_zero_node;
4705e4b17023SJohn Marino gcc_assert (fd.sched_kind != OMP_CLAUSE_SCHEDULE_AUTO);
4706e4b17023SJohn Marino fn_index = (fd.sched_kind == OMP_CLAUSE_SCHEDULE_RUNTIME)
4707e4b17023SJohn Marino ? 3 : fd.sched_kind;
4708e4b17023SJohn Marino fn_index += fd.have_ordered * 4;
4709e4b17023SJohn Marino start_ix = ((int)BUILT_IN_GOMP_LOOP_STATIC_START) + fn_index;
4710e4b17023SJohn Marino next_ix = ((int)BUILT_IN_GOMP_LOOP_STATIC_NEXT) + fn_index;
4711e4b17023SJohn Marino if (fd.iter_type == long_long_unsigned_type_node)
4712e4b17023SJohn Marino {
4713e4b17023SJohn Marino start_ix += ((int)BUILT_IN_GOMP_LOOP_ULL_STATIC_START
4714e4b17023SJohn Marino - (int)BUILT_IN_GOMP_LOOP_STATIC_START);
4715e4b17023SJohn Marino next_ix += ((int)BUILT_IN_GOMP_LOOP_ULL_STATIC_NEXT
4716e4b17023SJohn Marino - (int)BUILT_IN_GOMP_LOOP_STATIC_NEXT);
4717e4b17023SJohn Marino }
4718e4b17023SJohn Marino expand_omp_for_generic (region, &fd, (enum built_in_function) start_ix,
4719e4b17023SJohn Marino (enum built_in_function) next_ix);
4720e4b17023SJohn Marino }
4721e4b17023SJohn Marino
4722e4b17023SJohn Marino update_ssa (TODO_update_ssa_only_virtuals);
4723e4b17023SJohn Marino }
4724e4b17023SJohn Marino
4725e4b17023SJohn Marino
4726e4b17023SJohn Marino /* Expand code for an OpenMP sections directive. In pseudo code, we generate
4727e4b17023SJohn Marino
4728e4b17023SJohn Marino v = GOMP_sections_start (n);
4729e4b17023SJohn Marino L0:
4730e4b17023SJohn Marino switch (v)
4731e4b17023SJohn Marino {
4732e4b17023SJohn Marino case 0:
4733e4b17023SJohn Marino goto L2;
4734e4b17023SJohn Marino case 1:
4735e4b17023SJohn Marino section 1;
4736e4b17023SJohn Marino goto L1;
4737e4b17023SJohn Marino case 2:
4738e4b17023SJohn Marino ...
4739e4b17023SJohn Marino case n:
4740e4b17023SJohn Marino ...
4741e4b17023SJohn Marino default:
4742e4b17023SJohn Marino abort ();
4743e4b17023SJohn Marino }
4744e4b17023SJohn Marino L1:
4745e4b17023SJohn Marino v = GOMP_sections_next ();
4746e4b17023SJohn Marino goto L0;
4747e4b17023SJohn Marino L2:
4748e4b17023SJohn Marino reduction;
4749e4b17023SJohn Marino
4750e4b17023SJohn Marino If this is a combined parallel sections, replace the call to
4751e4b17023SJohn Marino GOMP_sections_start with call to GOMP_sections_next. */
4752e4b17023SJohn Marino
4753e4b17023SJohn Marino static void
expand_omp_sections(struct omp_region * region)4754e4b17023SJohn Marino expand_omp_sections (struct omp_region *region)
4755e4b17023SJohn Marino {
4756e4b17023SJohn Marino tree t, u, vin = NULL, vmain, vnext, l2;
4757e4b17023SJohn Marino VEC (tree,heap) *label_vec;
4758e4b17023SJohn Marino unsigned len;
4759e4b17023SJohn Marino basic_block entry_bb, l0_bb, l1_bb, l2_bb, default_bb;
4760e4b17023SJohn Marino gimple_stmt_iterator si, switch_si;
4761e4b17023SJohn Marino gimple sections_stmt, stmt, cont;
4762e4b17023SJohn Marino edge_iterator ei;
4763e4b17023SJohn Marino edge e;
4764e4b17023SJohn Marino struct omp_region *inner;
4765e4b17023SJohn Marino unsigned i, casei;
4766e4b17023SJohn Marino bool exit_reachable = region->cont != NULL;
4767e4b17023SJohn Marino
4768e4b17023SJohn Marino gcc_assert (region->exit != NULL);
4769e4b17023SJohn Marino entry_bb = region->entry;
4770e4b17023SJohn Marino l0_bb = single_succ (entry_bb);
4771e4b17023SJohn Marino l1_bb = region->cont;
4772e4b17023SJohn Marino l2_bb = region->exit;
4773e4b17023SJohn Marino if (single_pred_p (l2_bb) && single_pred (l2_bb) == l0_bb)
4774e4b17023SJohn Marino l2 = gimple_block_label (l2_bb);
4775e4b17023SJohn Marino else
4776e4b17023SJohn Marino {
4777e4b17023SJohn Marino /* This can happen if there are reductions. */
4778e4b17023SJohn Marino len = EDGE_COUNT (l0_bb->succs);
4779e4b17023SJohn Marino gcc_assert (len > 0);
4780e4b17023SJohn Marino e = EDGE_SUCC (l0_bb, len - 1);
4781e4b17023SJohn Marino si = gsi_last_bb (e->dest);
4782e4b17023SJohn Marino l2 = NULL_TREE;
4783e4b17023SJohn Marino if (gsi_end_p (si)
4784e4b17023SJohn Marino || gimple_code (gsi_stmt (si)) != GIMPLE_OMP_SECTION)
4785e4b17023SJohn Marino l2 = gimple_block_label (e->dest);
4786e4b17023SJohn Marino else
4787e4b17023SJohn Marino FOR_EACH_EDGE (e, ei, l0_bb->succs)
4788e4b17023SJohn Marino {
4789e4b17023SJohn Marino si = gsi_last_bb (e->dest);
4790e4b17023SJohn Marino if (gsi_end_p (si)
4791e4b17023SJohn Marino || gimple_code (gsi_stmt (si)) != GIMPLE_OMP_SECTION)
4792e4b17023SJohn Marino {
4793e4b17023SJohn Marino l2 = gimple_block_label (e->dest);
4794e4b17023SJohn Marino break;
4795e4b17023SJohn Marino }
4796e4b17023SJohn Marino }
4797e4b17023SJohn Marino }
4798e4b17023SJohn Marino if (exit_reachable)
4799e4b17023SJohn Marino default_bb = create_empty_bb (l1_bb->prev_bb);
4800e4b17023SJohn Marino else
4801e4b17023SJohn Marino default_bb = create_empty_bb (l0_bb);
4802e4b17023SJohn Marino
4803e4b17023SJohn Marino /* We will build a switch() with enough cases for all the
4804e4b17023SJohn Marino GIMPLE_OMP_SECTION regions, a '0' case to handle the end of more work
4805e4b17023SJohn Marino and a default case to abort if something goes wrong. */
4806e4b17023SJohn Marino len = EDGE_COUNT (l0_bb->succs);
4807e4b17023SJohn Marino
4808e4b17023SJohn Marino /* Use VEC_quick_push on label_vec throughout, since we know the size
4809e4b17023SJohn Marino in advance. */
4810e4b17023SJohn Marino label_vec = VEC_alloc (tree, heap, len);
4811e4b17023SJohn Marino
4812e4b17023SJohn Marino /* The call to GOMP_sections_start goes in ENTRY_BB, replacing the
4813e4b17023SJohn Marino GIMPLE_OMP_SECTIONS statement. */
4814e4b17023SJohn Marino si = gsi_last_bb (entry_bb);
4815e4b17023SJohn Marino sections_stmt = gsi_stmt (si);
4816e4b17023SJohn Marino gcc_assert (gimple_code (sections_stmt) == GIMPLE_OMP_SECTIONS);
4817e4b17023SJohn Marino vin = gimple_omp_sections_control (sections_stmt);
4818e4b17023SJohn Marino if (!is_combined_parallel (region))
4819e4b17023SJohn Marino {
4820e4b17023SJohn Marino /* If we are not inside a combined parallel+sections region,
4821e4b17023SJohn Marino call GOMP_sections_start. */
4822e4b17023SJohn Marino t = build_int_cst (unsigned_type_node,
4823e4b17023SJohn Marino exit_reachable ? len - 1 : len);
4824e4b17023SJohn Marino u = builtin_decl_explicit (BUILT_IN_GOMP_SECTIONS_START);
4825e4b17023SJohn Marino stmt = gimple_build_call (u, 1, t);
4826e4b17023SJohn Marino }
4827e4b17023SJohn Marino else
4828e4b17023SJohn Marino {
4829e4b17023SJohn Marino /* Otherwise, call GOMP_sections_next. */
4830e4b17023SJohn Marino u = builtin_decl_explicit (BUILT_IN_GOMP_SECTIONS_NEXT);
4831e4b17023SJohn Marino stmt = gimple_build_call (u, 0);
4832e4b17023SJohn Marino }
4833e4b17023SJohn Marino gimple_call_set_lhs (stmt, vin);
4834e4b17023SJohn Marino gsi_insert_after (&si, stmt, GSI_SAME_STMT);
4835e4b17023SJohn Marino gsi_remove (&si, true);
4836e4b17023SJohn Marino
4837e4b17023SJohn Marino /* The switch() statement replacing GIMPLE_OMP_SECTIONS_SWITCH goes in
4838e4b17023SJohn Marino L0_BB. */
4839e4b17023SJohn Marino switch_si = gsi_last_bb (l0_bb);
4840e4b17023SJohn Marino gcc_assert (gimple_code (gsi_stmt (switch_si)) == GIMPLE_OMP_SECTIONS_SWITCH);
4841e4b17023SJohn Marino if (exit_reachable)
4842e4b17023SJohn Marino {
4843e4b17023SJohn Marino cont = last_stmt (l1_bb);
4844e4b17023SJohn Marino gcc_assert (gimple_code (cont) == GIMPLE_OMP_CONTINUE);
4845e4b17023SJohn Marino vmain = gimple_omp_continue_control_use (cont);
4846e4b17023SJohn Marino vnext = gimple_omp_continue_control_def (cont);
4847e4b17023SJohn Marino }
4848e4b17023SJohn Marino else
4849e4b17023SJohn Marino {
4850e4b17023SJohn Marino vmain = vin;
4851e4b17023SJohn Marino vnext = NULL_TREE;
4852e4b17023SJohn Marino }
4853e4b17023SJohn Marino
4854e4b17023SJohn Marino t = build_case_label (build_int_cst (unsigned_type_node, 0), NULL, l2);
4855e4b17023SJohn Marino VEC_quick_push (tree, label_vec, t);
4856e4b17023SJohn Marino i = 1;
4857e4b17023SJohn Marino
4858e4b17023SJohn Marino /* Convert each GIMPLE_OMP_SECTION into a CASE_LABEL_EXPR. */
4859e4b17023SJohn Marino for (inner = region->inner, casei = 1;
4860e4b17023SJohn Marino inner;
4861e4b17023SJohn Marino inner = inner->next, i++, casei++)
4862e4b17023SJohn Marino {
4863e4b17023SJohn Marino basic_block s_entry_bb, s_exit_bb;
4864e4b17023SJohn Marino
4865e4b17023SJohn Marino /* Skip optional reduction region. */
4866e4b17023SJohn Marino if (inner->type == GIMPLE_OMP_ATOMIC_LOAD)
4867e4b17023SJohn Marino {
4868e4b17023SJohn Marino --i;
4869e4b17023SJohn Marino --casei;
4870e4b17023SJohn Marino continue;
4871e4b17023SJohn Marino }
4872e4b17023SJohn Marino
4873e4b17023SJohn Marino s_entry_bb = inner->entry;
4874e4b17023SJohn Marino s_exit_bb = inner->exit;
4875e4b17023SJohn Marino
4876e4b17023SJohn Marino t = gimple_block_label (s_entry_bb);
4877e4b17023SJohn Marino u = build_int_cst (unsigned_type_node, casei);
4878e4b17023SJohn Marino u = build_case_label (u, NULL, t);
4879e4b17023SJohn Marino VEC_quick_push (tree, label_vec, u);
4880e4b17023SJohn Marino
4881e4b17023SJohn Marino si = gsi_last_bb (s_entry_bb);
4882e4b17023SJohn Marino gcc_assert (gimple_code (gsi_stmt (si)) == GIMPLE_OMP_SECTION);
4883e4b17023SJohn Marino gcc_assert (i < len || gimple_omp_section_last_p (gsi_stmt (si)));
4884e4b17023SJohn Marino gsi_remove (&si, true);
4885e4b17023SJohn Marino single_succ_edge (s_entry_bb)->flags = EDGE_FALLTHRU;
4886e4b17023SJohn Marino
4887e4b17023SJohn Marino if (s_exit_bb == NULL)
4888e4b17023SJohn Marino continue;
4889e4b17023SJohn Marino
4890e4b17023SJohn Marino si = gsi_last_bb (s_exit_bb);
4891e4b17023SJohn Marino gcc_assert (gimple_code (gsi_stmt (si)) == GIMPLE_OMP_RETURN);
4892e4b17023SJohn Marino gsi_remove (&si, true);
4893e4b17023SJohn Marino
4894e4b17023SJohn Marino single_succ_edge (s_exit_bb)->flags = EDGE_FALLTHRU;
4895e4b17023SJohn Marino }
4896e4b17023SJohn Marino
4897e4b17023SJohn Marino /* Error handling code goes in DEFAULT_BB. */
4898e4b17023SJohn Marino t = gimple_block_label (default_bb);
4899e4b17023SJohn Marino u = build_case_label (NULL, NULL, t);
4900e4b17023SJohn Marino make_edge (l0_bb, default_bb, 0);
4901e4b17023SJohn Marino
4902e4b17023SJohn Marino stmt = gimple_build_switch_vec (vmain, u, label_vec);
4903e4b17023SJohn Marino gsi_insert_after (&switch_si, stmt, GSI_SAME_STMT);
4904e4b17023SJohn Marino gsi_remove (&switch_si, true);
4905e4b17023SJohn Marino VEC_free (tree, heap, label_vec);
4906e4b17023SJohn Marino
4907e4b17023SJohn Marino si = gsi_start_bb (default_bb);
4908e4b17023SJohn Marino stmt = gimple_build_call (builtin_decl_explicit (BUILT_IN_TRAP), 0);
4909e4b17023SJohn Marino gsi_insert_after (&si, stmt, GSI_CONTINUE_LINKING);
4910e4b17023SJohn Marino
4911e4b17023SJohn Marino if (exit_reachable)
4912e4b17023SJohn Marino {
4913e4b17023SJohn Marino tree bfn_decl;
4914e4b17023SJohn Marino
4915e4b17023SJohn Marino /* Code to get the next section goes in L1_BB. */
4916e4b17023SJohn Marino si = gsi_last_bb (l1_bb);
4917e4b17023SJohn Marino gcc_assert (gimple_code (gsi_stmt (si)) == GIMPLE_OMP_CONTINUE);
4918e4b17023SJohn Marino
4919e4b17023SJohn Marino bfn_decl = builtin_decl_explicit (BUILT_IN_GOMP_SECTIONS_NEXT);
4920e4b17023SJohn Marino stmt = gimple_build_call (bfn_decl, 0);
4921e4b17023SJohn Marino gimple_call_set_lhs (stmt, vnext);
4922e4b17023SJohn Marino gsi_insert_after (&si, stmt, GSI_SAME_STMT);
4923e4b17023SJohn Marino gsi_remove (&si, true);
4924e4b17023SJohn Marino
4925e4b17023SJohn Marino single_succ_edge (l1_bb)->flags = EDGE_FALLTHRU;
4926e4b17023SJohn Marino }
4927e4b17023SJohn Marino
4928e4b17023SJohn Marino /* Cleanup function replaces GIMPLE_OMP_RETURN in EXIT_BB. */
4929e4b17023SJohn Marino si = gsi_last_bb (l2_bb);
4930e4b17023SJohn Marino if (gimple_omp_return_nowait_p (gsi_stmt (si)))
4931e4b17023SJohn Marino t = builtin_decl_explicit (BUILT_IN_GOMP_SECTIONS_END_NOWAIT);
4932e4b17023SJohn Marino else
4933e4b17023SJohn Marino t = builtin_decl_explicit (BUILT_IN_GOMP_SECTIONS_END);
4934e4b17023SJohn Marino stmt = gimple_build_call (t, 0);
4935e4b17023SJohn Marino gsi_insert_after (&si, stmt, GSI_SAME_STMT);
4936e4b17023SJohn Marino gsi_remove (&si, true);
4937e4b17023SJohn Marino
4938e4b17023SJohn Marino set_immediate_dominator (CDI_DOMINATORS, default_bb, l0_bb);
4939e4b17023SJohn Marino }
4940e4b17023SJohn Marino
4941e4b17023SJohn Marino
4942e4b17023SJohn Marino /* Expand code for an OpenMP single directive. We've already expanded
4943e4b17023SJohn Marino much of the code, here we simply place the GOMP_barrier call. */
4944e4b17023SJohn Marino
4945e4b17023SJohn Marino static void
expand_omp_single(struct omp_region * region)4946e4b17023SJohn Marino expand_omp_single (struct omp_region *region)
4947e4b17023SJohn Marino {
4948e4b17023SJohn Marino basic_block entry_bb, exit_bb;
4949e4b17023SJohn Marino gimple_stmt_iterator si;
4950e4b17023SJohn Marino bool need_barrier = false;
4951e4b17023SJohn Marino
4952e4b17023SJohn Marino entry_bb = region->entry;
4953e4b17023SJohn Marino exit_bb = region->exit;
4954e4b17023SJohn Marino
4955e4b17023SJohn Marino si = gsi_last_bb (entry_bb);
4956e4b17023SJohn Marino /* The terminal barrier at the end of a GOMP_single_copy sequence cannot
4957e4b17023SJohn Marino be removed. We need to ensure that the thread that entered the single
4958e4b17023SJohn Marino does not exit before the data is copied out by the other threads. */
4959e4b17023SJohn Marino if (find_omp_clause (gimple_omp_single_clauses (gsi_stmt (si)),
4960e4b17023SJohn Marino OMP_CLAUSE_COPYPRIVATE))
4961e4b17023SJohn Marino need_barrier = true;
4962e4b17023SJohn Marino gcc_assert (gimple_code (gsi_stmt (si)) == GIMPLE_OMP_SINGLE);
4963e4b17023SJohn Marino gsi_remove (&si, true);
4964e4b17023SJohn Marino single_succ_edge (entry_bb)->flags = EDGE_FALLTHRU;
4965e4b17023SJohn Marino
4966e4b17023SJohn Marino si = gsi_last_bb (exit_bb);
4967e4b17023SJohn Marino if (!gimple_omp_return_nowait_p (gsi_stmt (si)) || need_barrier)
4968e4b17023SJohn Marino force_gimple_operand_gsi (&si, build_omp_barrier (), false, NULL_TREE,
4969e4b17023SJohn Marino false, GSI_SAME_STMT);
4970e4b17023SJohn Marino gsi_remove (&si, true);
4971e4b17023SJohn Marino single_succ_edge (exit_bb)->flags = EDGE_FALLTHRU;
4972e4b17023SJohn Marino }
4973e4b17023SJohn Marino
4974e4b17023SJohn Marino
4975e4b17023SJohn Marino /* Generic expansion for OpenMP synchronization directives: master,
4976e4b17023SJohn Marino ordered and critical. All we need to do here is remove the entry
4977e4b17023SJohn Marino and exit markers for REGION. */
4978e4b17023SJohn Marino
4979e4b17023SJohn Marino static void
expand_omp_synch(struct omp_region * region)4980e4b17023SJohn Marino expand_omp_synch (struct omp_region *region)
4981e4b17023SJohn Marino {
4982e4b17023SJohn Marino basic_block entry_bb, exit_bb;
4983e4b17023SJohn Marino gimple_stmt_iterator si;
4984e4b17023SJohn Marino
4985e4b17023SJohn Marino entry_bb = region->entry;
4986e4b17023SJohn Marino exit_bb = region->exit;
4987e4b17023SJohn Marino
4988e4b17023SJohn Marino si = gsi_last_bb (entry_bb);
4989e4b17023SJohn Marino gcc_assert (gimple_code (gsi_stmt (si)) == GIMPLE_OMP_SINGLE
4990e4b17023SJohn Marino || gimple_code (gsi_stmt (si)) == GIMPLE_OMP_MASTER
4991e4b17023SJohn Marino || gimple_code (gsi_stmt (si)) == GIMPLE_OMP_ORDERED
4992e4b17023SJohn Marino || gimple_code (gsi_stmt (si)) == GIMPLE_OMP_CRITICAL);
4993e4b17023SJohn Marino gsi_remove (&si, true);
4994e4b17023SJohn Marino single_succ_edge (entry_bb)->flags = EDGE_FALLTHRU;
4995e4b17023SJohn Marino
4996e4b17023SJohn Marino if (exit_bb)
4997e4b17023SJohn Marino {
4998e4b17023SJohn Marino si = gsi_last_bb (exit_bb);
4999e4b17023SJohn Marino gcc_assert (gimple_code (gsi_stmt (si)) == GIMPLE_OMP_RETURN);
5000e4b17023SJohn Marino gsi_remove (&si, true);
5001e4b17023SJohn Marino single_succ_edge (exit_bb)->flags = EDGE_FALLTHRU;
5002e4b17023SJohn Marino }
5003e4b17023SJohn Marino }
5004e4b17023SJohn Marino
5005e4b17023SJohn Marino /* A subroutine of expand_omp_atomic. Attempt to implement the atomic
5006e4b17023SJohn Marino operation as a normal volatile load. */
5007e4b17023SJohn Marino
5008e4b17023SJohn Marino static bool
expand_omp_atomic_load(basic_block load_bb,tree addr,tree loaded_val,int index)5009e4b17023SJohn Marino expand_omp_atomic_load (basic_block load_bb, tree addr,
5010e4b17023SJohn Marino tree loaded_val, int index)
5011e4b17023SJohn Marino {
5012e4b17023SJohn Marino enum built_in_function tmpbase;
5013e4b17023SJohn Marino gimple_stmt_iterator gsi;
5014e4b17023SJohn Marino basic_block store_bb;
5015e4b17023SJohn Marino location_t loc;
5016e4b17023SJohn Marino gimple stmt;
5017e4b17023SJohn Marino tree decl, call, type, itype;
5018e4b17023SJohn Marino
5019e4b17023SJohn Marino gsi = gsi_last_bb (load_bb);
5020e4b17023SJohn Marino stmt = gsi_stmt (gsi);
5021e4b17023SJohn Marino gcc_assert (gimple_code (stmt) == GIMPLE_OMP_ATOMIC_LOAD);
5022e4b17023SJohn Marino loc = gimple_location (stmt);
5023e4b17023SJohn Marino
5024e4b17023SJohn Marino /* ??? If the target does not implement atomic_load_optab[mode], and mode
5025e4b17023SJohn Marino is smaller than word size, then expand_atomic_load assumes that the load
5026e4b17023SJohn Marino is atomic. We could avoid the builtin entirely in this case. */
5027e4b17023SJohn Marino
5028e4b17023SJohn Marino tmpbase = (enum built_in_function) (BUILT_IN_ATOMIC_LOAD_N + index + 1);
5029e4b17023SJohn Marino decl = builtin_decl_explicit (tmpbase);
5030e4b17023SJohn Marino if (decl == NULL_TREE)
5031e4b17023SJohn Marino return false;
5032e4b17023SJohn Marino
5033e4b17023SJohn Marino type = TREE_TYPE (loaded_val);
5034e4b17023SJohn Marino itype = TREE_TYPE (TREE_TYPE (decl));
5035e4b17023SJohn Marino
5036e4b17023SJohn Marino call = build_call_expr_loc (loc, decl, 2, addr,
5037e4b17023SJohn Marino build_int_cst (NULL, MEMMODEL_RELAXED));
5038e4b17023SJohn Marino if (!useless_type_conversion_p (type, itype))
5039e4b17023SJohn Marino call = fold_build1_loc (loc, VIEW_CONVERT_EXPR, type, call);
5040e4b17023SJohn Marino call = build2_loc (loc, MODIFY_EXPR, void_type_node, loaded_val, call);
5041e4b17023SJohn Marino
5042e4b17023SJohn Marino force_gimple_operand_gsi (&gsi, call, true, NULL_TREE, true, GSI_SAME_STMT);
5043e4b17023SJohn Marino gsi_remove (&gsi, true);
5044e4b17023SJohn Marino
5045e4b17023SJohn Marino store_bb = single_succ (load_bb);
5046e4b17023SJohn Marino gsi = gsi_last_bb (store_bb);
5047e4b17023SJohn Marino gcc_assert (gimple_code (gsi_stmt (gsi)) == GIMPLE_OMP_ATOMIC_STORE);
5048e4b17023SJohn Marino gsi_remove (&gsi, true);
5049e4b17023SJohn Marino
5050e4b17023SJohn Marino if (gimple_in_ssa_p (cfun))
5051e4b17023SJohn Marino update_ssa (TODO_update_ssa_no_phi);
5052e4b17023SJohn Marino
5053e4b17023SJohn Marino return true;
5054e4b17023SJohn Marino }
5055e4b17023SJohn Marino
5056e4b17023SJohn Marino /* A subroutine of expand_omp_atomic. Attempt to implement the atomic
5057e4b17023SJohn Marino operation as a normal volatile store. */
5058e4b17023SJohn Marino
5059e4b17023SJohn Marino static bool
expand_omp_atomic_store(basic_block load_bb,tree addr,tree loaded_val,tree stored_val,int index)5060e4b17023SJohn Marino expand_omp_atomic_store (basic_block load_bb, tree addr,
5061e4b17023SJohn Marino tree loaded_val, tree stored_val, int index)
5062e4b17023SJohn Marino {
5063e4b17023SJohn Marino enum built_in_function tmpbase;
5064e4b17023SJohn Marino gimple_stmt_iterator gsi;
5065e4b17023SJohn Marino basic_block store_bb = single_succ (load_bb);
5066e4b17023SJohn Marino location_t loc;
5067e4b17023SJohn Marino gimple stmt;
5068e4b17023SJohn Marino tree decl, call, type, itype;
5069e4b17023SJohn Marino enum machine_mode imode;
5070e4b17023SJohn Marino bool exchange;
5071e4b17023SJohn Marino
5072e4b17023SJohn Marino gsi = gsi_last_bb (load_bb);
5073e4b17023SJohn Marino stmt = gsi_stmt (gsi);
5074e4b17023SJohn Marino gcc_assert (gimple_code (stmt) == GIMPLE_OMP_ATOMIC_LOAD);
5075e4b17023SJohn Marino
5076e4b17023SJohn Marino /* If the load value is needed, then this isn't a store but an exchange. */
5077e4b17023SJohn Marino exchange = gimple_omp_atomic_need_value_p (stmt);
5078e4b17023SJohn Marino
5079e4b17023SJohn Marino gsi = gsi_last_bb (store_bb);
5080e4b17023SJohn Marino stmt = gsi_stmt (gsi);
5081e4b17023SJohn Marino gcc_assert (gimple_code (stmt) == GIMPLE_OMP_ATOMIC_STORE);
5082e4b17023SJohn Marino loc = gimple_location (stmt);
5083e4b17023SJohn Marino
5084e4b17023SJohn Marino /* ??? If the target does not implement atomic_store_optab[mode], and mode
5085e4b17023SJohn Marino is smaller than word size, then expand_atomic_store assumes that the store
5086e4b17023SJohn Marino is atomic. We could avoid the builtin entirely in this case. */
5087e4b17023SJohn Marino
5088e4b17023SJohn Marino tmpbase = (exchange ? BUILT_IN_ATOMIC_EXCHANGE_N : BUILT_IN_ATOMIC_STORE_N);
5089e4b17023SJohn Marino tmpbase = (enum built_in_function) ((int) tmpbase + index + 1);
5090e4b17023SJohn Marino decl = builtin_decl_explicit (tmpbase);
5091e4b17023SJohn Marino if (decl == NULL_TREE)
5092e4b17023SJohn Marino return false;
5093e4b17023SJohn Marino
5094e4b17023SJohn Marino type = TREE_TYPE (stored_val);
5095e4b17023SJohn Marino
5096e4b17023SJohn Marino /* Dig out the type of the function's second argument. */
5097e4b17023SJohn Marino itype = TREE_TYPE (decl);
5098e4b17023SJohn Marino itype = TYPE_ARG_TYPES (itype);
5099e4b17023SJohn Marino itype = TREE_CHAIN (itype);
5100e4b17023SJohn Marino itype = TREE_VALUE (itype);
5101e4b17023SJohn Marino imode = TYPE_MODE (itype);
5102e4b17023SJohn Marino
5103e4b17023SJohn Marino if (exchange && !can_atomic_exchange_p (imode, true))
5104e4b17023SJohn Marino return false;
5105e4b17023SJohn Marino
5106e4b17023SJohn Marino if (!useless_type_conversion_p (itype, type))
5107e4b17023SJohn Marino stored_val = fold_build1_loc (loc, VIEW_CONVERT_EXPR, itype, stored_val);
5108e4b17023SJohn Marino call = build_call_expr_loc (loc, decl, 3, addr, stored_val,
5109e4b17023SJohn Marino build_int_cst (NULL, MEMMODEL_RELAXED));
5110e4b17023SJohn Marino if (exchange)
5111e4b17023SJohn Marino {
5112e4b17023SJohn Marino if (!useless_type_conversion_p (type, itype))
5113e4b17023SJohn Marino call = build1_loc (loc, VIEW_CONVERT_EXPR, type, call);
5114e4b17023SJohn Marino call = build2_loc (loc, MODIFY_EXPR, void_type_node, loaded_val, call);
5115e4b17023SJohn Marino }
5116e4b17023SJohn Marino
5117e4b17023SJohn Marino force_gimple_operand_gsi (&gsi, call, true, NULL_TREE, true, GSI_SAME_STMT);
5118e4b17023SJohn Marino gsi_remove (&gsi, true);
5119e4b17023SJohn Marino
5120e4b17023SJohn Marino /* Remove the GIMPLE_OMP_ATOMIC_LOAD that we verified above. */
5121e4b17023SJohn Marino gsi = gsi_last_bb (load_bb);
5122e4b17023SJohn Marino gsi_remove (&gsi, true);
5123e4b17023SJohn Marino
5124e4b17023SJohn Marino if (gimple_in_ssa_p (cfun))
5125e4b17023SJohn Marino update_ssa (TODO_update_ssa_no_phi);
5126e4b17023SJohn Marino
5127e4b17023SJohn Marino return true;
5128e4b17023SJohn Marino }
5129e4b17023SJohn Marino
5130e4b17023SJohn Marino /* A subroutine of expand_omp_atomic. Attempt to implement the atomic
5131e4b17023SJohn Marino operation as a __atomic_fetch_op builtin. INDEX is log2 of the
5132e4b17023SJohn Marino size of the data type, and thus usable to find the index of the builtin
5133e4b17023SJohn Marino decl. Returns false if the expression is not of the proper form. */
5134e4b17023SJohn Marino
5135e4b17023SJohn Marino static bool
expand_omp_atomic_fetch_op(basic_block load_bb,tree addr,tree loaded_val,tree stored_val,int index)5136e4b17023SJohn Marino expand_omp_atomic_fetch_op (basic_block load_bb,
5137e4b17023SJohn Marino tree addr, tree loaded_val,
5138e4b17023SJohn Marino tree stored_val, int index)
5139e4b17023SJohn Marino {
5140e4b17023SJohn Marino enum built_in_function oldbase, newbase, tmpbase;
5141e4b17023SJohn Marino tree decl, itype, call;
5142e4b17023SJohn Marino tree lhs, rhs;
5143e4b17023SJohn Marino basic_block store_bb = single_succ (load_bb);
5144e4b17023SJohn Marino gimple_stmt_iterator gsi;
5145e4b17023SJohn Marino gimple stmt;
5146e4b17023SJohn Marino location_t loc;
5147e4b17023SJohn Marino enum tree_code code;
5148e4b17023SJohn Marino bool need_old, need_new;
5149e4b17023SJohn Marino enum machine_mode imode;
5150e4b17023SJohn Marino
5151e4b17023SJohn Marino /* We expect to find the following sequences:
5152e4b17023SJohn Marino
5153e4b17023SJohn Marino load_bb:
5154e4b17023SJohn Marino GIMPLE_OMP_ATOMIC_LOAD (tmp, mem)
5155e4b17023SJohn Marino
5156e4b17023SJohn Marino store_bb:
5157e4b17023SJohn Marino val = tmp OP something; (or: something OP tmp)
5158e4b17023SJohn Marino GIMPLE_OMP_STORE (val)
5159e4b17023SJohn Marino
5160e4b17023SJohn Marino ???FIXME: Allow a more flexible sequence.
5161e4b17023SJohn Marino Perhaps use data flow to pick the statements.
5162e4b17023SJohn Marino
5163e4b17023SJohn Marino */
5164e4b17023SJohn Marino
5165e4b17023SJohn Marino gsi = gsi_after_labels (store_bb);
5166e4b17023SJohn Marino stmt = gsi_stmt (gsi);
5167e4b17023SJohn Marino loc = gimple_location (stmt);
5168e4b17023SJohn Marino if (!is_gimple_assign (stmt))
5169e4b17023SJohn Marino return false;
5170e4b17023SJohn Marino gsi_next (&gsi);
5171e4b17023SJohn Marino if (gimple_code (gsi_stmt (gsi)) != GIMPLE_OMP_ATOMIC_STORE)
5172e4b17023SJohn Marino return false;
5173e4b17023SJohn Marino need_new = gimple_omp_atomic_need_value_p (gsi_stmt (gsi));
5174e4b17023SJohn Marino need_old = gimple_omp_atomic_need_value_p (last_stmt (load_bb));
5175e4b17023SJohn Marino gcc_checking_assert (!need_old || !need_new);
5176e4b17023SJohn Marino
5177e4b17023SJohn Marino if (!operand_equal_p (gimple_assign_lhs (stmt), stored_val, 0))
5178e4b17023SJohn Marino return false;
5179e4b17023SJohn Marino
5180e4b17023SJohn Marino /* Check for one of the supported fetch-op operations. */
5181e4b17023SJohn Marino code = gimple_assign_rhs_code (stmt);
5182e4b17023SJohn Marino switch (code)
5183e4b17023SJohn Marino {
5184e4b17023SJohn Marino case PLUS_EXPR:
5185e4b17023SJohn Marino case POINTER_PLUS_EXPR:
5186e4b17023SJohn Marino oldbase = BUILT_IN_ATOMIC_FETCH_ADD_N;
5187e4b17023SJohn Marino newbase = BUILT_IN_ATOMIC_ADD_FETCH_N;
5188e4b17023SJohn Marino break;
5189e4b17023SJohn Marino case MINUS_EXPR:
5190e4b17023SJohn Marino oldbase = BUILT_IN_ATOMIC_FETCH_SUB_N;
5191e4b17023SJohn Marino newbase = BUILT_IN_ATOMIC_SUB_FETCH_N;
5192e4b17023SJohn Marino break;
5193e4b17023SJohn Marino case BIT_AND_EXPR:
5194e4b17023SJohn Marino oldbase = BUILT_IN_ATOMIC_FETCH_AND_N;
5195e4b17023SJohn Marino newbase = BUILT_IN_ATOMIC_AND_FETCH_N;
5196e4b17023SJohn Marino break;
5197e4b17023SJohn Marino case BIT_IOR_EXPR:
5198e4b17023SJohn Marino oldbase = BUILT_IN_ATOMIC_FETCH_OR_N;
5199e4b17023SJohn Marino newbase = BUILT_IN_ATOMIC_OR_FETCH_N;
5200e4b17023SJohn Marino break;
5201e4b17023SJohn Marino case BIT_XOR_EXPR:
5202e4b17023SJohn Marino oldbase = BUILT_IN_ATOMIC_FETCH_XOR_N;
5203e4b17023SJohn Marino newbase = BUILT_IN_ATOMIC_XOR_FETCH_N;
5204e4b17023SJohn Marino break;
5205e4b17023SJohn Marino default:
5206e4b17023SJohn Marino return false;
5207e4b17023SJohn Marino }
5208e4b17023SJohn Marino
5209e4b17023SJohn Marino /* Make sure the expression is of the proper form. */
5210e4b17023SJohn Marino if (operand_equal_p (gimple_assign_rhs1 (stmt), loaded_val, 0))
5211e4b17023SJohn Marino rhs = gimple_assign_rhs2 (stmt);
5212e4b17023SJohn Marino else if (commutative_tree_code (gimple_assign_rhs_code (stmt))
5213e4b17023SJohn Marino && operand_equal_p (gimple_assign_rhs2 (stmt), loaded_val, 0))
5214e4b17023SJohn Marino rhs = gimple_assign_rhs1 (stmt);
5215e4b17023SJohn Marino else
5216e4b17023SJohn Marino return false;
5217e4b17023SJohn Marino
5218e4b17023SJohn Marino tmpbase = ((enum built_in_function)
5219e4b17023SJohn Marino ((need_new ? newbase : oldbase) + index + 1));
5220e4b17023SJohn Marino decl = builtin_decl_explicit (tmpbase);
5221e4b17023SJohn Marino if (decl == NULL_TREE)
5222e4b17023SJohn Marino return false;
5223e4b17023SJohn Marino itype = TREE_TYPE (TREE_TYPE (decl));
5224e4b17023SJohn Marino imode = TYPE_MODE (itype);
5225e4b17023SJohn Marino
5226e4b17023SJohn Marino /* We could test all of the various optabs involved, but the fact of the
5227e4b17023SJohn Marino matter is that (with the exception of i486 vs i586 and xadd) all targets
5228e4b17023SJohn Marino that support any atomic operaton optab also implements compare-and-swap.
5229e4b17023SJohn Marino Let optabs.c take care of expanding any compare-and-swap loop. */
5230e4b17023SJohn Marino if (!can_compare_and_swap_p (imode, true))
5231e4b17023SJohn Marino return false;
5232e4b17023SJohn Marino
5233e4b17023SJohn Marino gsi = gsi_last_bb (load_bb);
5234e4b17023SJohn Marino gcc_assert (gimple_code (gsi_stmt (gsi)) == GIMPLE_OMP_ATOMIC_LOAD);
5235e4b17023SJohn Marino
5236e4b17023SJohn Marino /* OpenMP does not imply any barrier-like semantics on its atomic ops.
5237e4b17023SJohn Marino It only requires that the operation happen atomically. Thus we can
5238e4b17023SJohn Marino use the RELAXED memory model. */
5239e4b17023SJohn Marino call = build_call_expr_loc (loc, decl, 3, addr,
5240e4b17023SJohn Marino fold_convert_loc (loc, itype, rhs),
5241e4b17023SJohn Marino build_int_cst (NULL, MEMMODEL_RELAXED));
5242e4b17023SJohn Marino
5243e4b17023SJohn Marino if (need_old || need_new)
5244e4b17023SJohn Marino {
5245e4b17023SJohn Marino lhs = need_old ? loaded_val : stored_val;
5246e4b17023SJohn Marino call = fold_convert_loc (loc, TREE_TYPE (lhs), call);
5247e4b17023SJohn Marino call = build2_loc (loc, MODIFY_EXPR, void_type_node, lhs, call);
5248e4b17023SJohn Marino }
5249e4b17023SJohn Marino else
5250e4b17023SJohn Marino call = fold_convert_loc (loc, void_type_node, call);
5251e4b17023SJohn Marino force_gimple_operand_gsi (&gsi, call, true, NULL_TREE, true, GSI_SAME_STMT);
5252e4b17023SJohn Marino gsi_remove (&gsi, true);
5253e4b17023SJohn Marino
5254e4b17023SJohn Marino gsi = gsi_last_bb (store_bb);
5255e4b17023SJohn Marino gcc_assert (gimple_code (gsi_stmt (gsi)) == GIMPLE_OMP_ATOMIC_STORE);
5256e4b17023SJohn Marino gsi_remove (&gsi, true);
5257e4b17023SJohn Marino gsi = gsi_last_bb (store_bb);
5258e4b17023SJohn Marino gsi_remove (&gsi, true);
5259e4b17023SJohn Marino
5260e4b17023SJohn Marino if (gimple_in_ssa_p (cfun))
5261e4b17023SJohn Marino update_ssa (TODO_update_ssa_no_phi);
5262e4b17023SJohn Marino
5263e4b17023SJohn Marino return true;
5264e4b17023SJohn Marino }
5265e4b17023SJohn Marino
5266e4b17023SJohn Marino /* A subroutine of expand_omp_atomic. Implement the atomic operation as:
5267e4b17023SJohn Marino
5268e4b17023SJohn Marino oldval = *addr;
5269e4b17023SJohn Marino repeat:
5270e4b17023SJohn Marino newval = rhs; // with oldval replacing *addr in rhs
5271e4b17023SJohn Marino oldval = __sync_val_compare_and_swap (addr, oldval, newval);
5272e4b17023SJohn Marino if (oldval != newval)
5273e4b17023SJohn Marino goto repeat;
5274e4b17023SJohn Marino
5275e4b17023SJohn Marino INDEX is log2 of the size of the data type, and thus usable to find the
5276e4b17023SJohn Marino index of the builtin decl. */
5277e4b17023SJohn Marino
5278e4b17023SJohn Marino static bool
expand_omp_atomic_pipeline(basic_block load_bb,basic_block store_bb,tree addr,tree loaded_val,tree stored_val,int index)5279e4b17023SJohn Marino expand_omp_atomic_pipeline (basic_block load_bb, basic_block store_bb,
5280e4b17023SJohn Marino tree addr, tree loaded_val, tree stored_val,
5281e4b17023SJohn Marino int index)
5282e4b17023SJohn Marino {
5283e4b17023SJohn Marino tree loadedi, storedi, initial, new_storedi, old_vali;
5284e4b17023SJohn Marino tree type, itype, cmpxchg, iaddr;
5285e4b17023SJohn Marino gimple_stmt_iterator si;
5286e4b17023SJohn Marino basic_block loop_header = single_succ (load_bb);
5287e4b17023SJohn Marino gimple phi, stmt;
5288e4b17023SJohn Marino edge e;
5289e4b17023SJohn Marino enum built_in_function fncode;
5290e4b17023SJohn Marino
5291e4b17023SJohn Marino /* ??? We need a non-pointer interface to __atomic_compare_exchange in
5292e4b17023SJohn Marino order to use the RELAXED memory model effectively. */
5293e4b17023SJohn Marino fncode = (enum built_in_function)((int)BUILT_IN_SYNC_VAL_COMPARE_AND_SWAP_N
5294e4b17023SJohn Marino + index + 1);
5295e4b17023SJohn Marino cmpxchg = builtin_decl_explicit (fncode);
5296e4b17023SJohn Marino if (cmpxchg == NULL_TREE)
5297e4b17023SJohn Marino return false;
5298e4b17023SJohn Marino type = TYPE_MAIN_VARIANT (TREE_TYPE (TREE_TYPE (addr)));
5299e4b17023SJohn Marino itype = TREE_TYPE (TREE_TYPE (cmpxchg));
5300e4b17023SJohn Marino
5301e4b17023SJohn Marino if (!can_compare_and_swap_p (TYPE_MODE (itype), true))
5302e4b17023SJohn Marino return false;
5303e4b17023SJohn Marino
5304e4b17023SJohn Marino /* Load the initial value, replacing the GIMPLE_OMP_ATOMIC_LOAD. */
5305e4b17023SJohn Marino si = gsi_last_bb (load_bb);
5306e4b17023SJohn Marino gcc_assert (gimple_code (gsi_stmt (si)) == GIMPLE_OMP_ATOMIC_LOAD);
5307e4b17023SJohn Marino
5308e4b17023SJohn Marino /* For floating-point values, we'll need to view-convert them to integers
5309e4b17023SJohn Marino so that we can perform the atomic compare and swap. Simplify the
5310e4b17023SJohn Marino following code by always setting up the "i"ntegral variables. */
5311e4b17023SJohn Marino if (!INTEGRAL_TYPE_P (type) && !POINTER_TYPE_P (type))
5312e4b17023SJohn Marino {
5313e4b17023SJohn Marino tree iaddr_val;
5314e4b17023SJohn Marino
5315e4b17023SJohn Marino iaddr = create_tmp_var (build_pointer_type_for_mode (itype, ptr_mode,
5316e4b17023SJohn Marino true), NULL);
5317e4b17023SJohn Marino iaddr_val
5318e4b17023SJohn Marino = force_gimple_operand_gsi (&si,
5319e4b17023SJohn Marino fold_convert (TREE_TYPE (iaddr), addr),
5320e4b17023SJohn Marino false, NULL_TREE, true, GSI_SAME_STMT);
5321e4b17023SJohn Marino stmt = gimple_build_assign (iaddr, iaddr_val);
5322e4b17023SJohn Marino gsi_insert_before (&si, stmt, GSI_SAME_STMT);
5323e4b17023SJohn Marino loadedi = create_tmp_var (itype, NULL);
5324e4b17023SJohn Marino if (gimple_in_ssa_p (cfun))
5325e4b17023SJohn Marino {
5326e4b17023SJohn Marino add_referenced_var (iaddr);
5327e4b17023SJohn Marino add_referenced_var (loadedi);
5328e4b17023SJohn Marino loadedi = make_ssa_name (loadedi, NULL);
5329e4b17023SJohn Marino }
5330e4b17023SJohn Marino }
5331e4b17023SJohn Marino else
5332e4b17023SJohn Marino {
5333e4b17023SJohn Marino iaddr = addr;
5334e4b17023SJohn Marino loadedi = loaded_val;
5335e4b17023SJohn Marino }
5336e4b17023SJohn Marino
5337e4b17023SJohn Marino initial
5338e4b17023SJohn Marino = force_gimple_operand_gsi (&si,
5339e4b17023SJohn Marino build2 (MEM_REF, TREE_TYPE (TREE_TYPE (iaddr)),
5340e4b17023SJohn Marino iaddr,
5341e4b17023SJohn Marino build_int_cst (TREE_TYPE (iaddr), 0)),
5342e4b17023SJohn Marino true, NULL_TREE, true, GSI_SAME_STMT);
5343e4b17023SJohn Marino
5344e4b17023SJohn Marino /* Move the value to the LOADEDI temporary. */
5345e4b17023SJohn Marino if (gimple_in_ssa_p (cfun))
5346e4b17023SJohn Marino {
5347e4b17023SJohn Marino gcc_assert (gimple_seq_empty_p (phi_nodes (loop_header)));
5348e4b17023SJohn Marino phi = create_phi_node (loadedi, loop_header);
5349e4b17023SJohn Marino SSA_NAME_DEF_STMT (loadedi) = phi;
5350e4b17023SJohn Marino SET_USE (PHI_ARG_DEF_PTR_FROM_EDGE (phi, single_succ_edge (load_bb)),
5351e4b17023SJohn Marino initial);
5352e4b17023SJohn Marino }
5353e4b17023SJohn Marino else
5354e4b17023SJohn Marino gsi_insert_before (&si,
5355e4b17023SJohn Marino gimple_build_assign (loadedi, initial),
5356e4b17023SJohn Marino GSI_SAME_STMT);
5357e4b17023SJohn Marino if (loadedi != loaded_val)
5358e4b17023SJohn Marino {
5359e4b17023SJohn Marino gimple_stmt_iterator gsi2;
5360e4b17023SJohn Marino tree x;
5361e4b17023SJohn Marino
5362e4b17023SJohn Marino x = build1 (VIEW_CONVERT_EXPR, type, loadedi);
5363e4b17023SJohn Marino gsi2 = gsi_start_bb (loop_header);
5364e4b17023SJohn Marino if (gimple_in_ssa_p (cfun))
5365e4b17023SJohn Marino {
5366e4b17023SJohn Marino gimple stmt;
5367e4b17023SJohn Marino x = force_gimple_operand_gsi (&gsi2, x, true, NULL_TREE,
5368e4b17023SJohn Marino true, GSI_SAME_STMT);
5369e4b17023SJohn Marino stmt = gimple_build_assign (loaded_val, x);
5370e4b17023SJohn Marino gsi_insert_before (&gsi2, stmt, GSI_SAME_STMT);
5371e4b17023SJohn Marino }
5372e4b17023SJohn Marino else
5373e4b17023SJohn Marino {
5374e4b17023SJohn Marino x = build2 (MODIFY_EXPR, TREE_TYPE (loaded_val), loaded_val, x);
5375e4b17023SJohn Marino force_gimple_operand_gsi (&gsi2, x, true, NULL_TREE,
5376e4b17023SJohn Marino true, GSI_SAME_STMT);
5377e4b17023SJohn Marino }
5378e4b17023SJohn Marino }
5379e4b17023SJohn Marino gsi_remove (&si, true);
5380e4b17023SJohn Marino
5381e4b17023SJohn Marino si = gsi_last_bb (store_bb);
5382e4b17023SJohn Marino gcc_assert (gimple_code (gsi_stmt (si)) == GIMPLE_OMP_ATOMIC_STORE);
5383e4b17023SJohn Marino
5384e4b17023SJohn Marino if (iaddr == addr)
5385e4b17023SJohn Marino storedi = stored_val;
5386e4b17023SJohn Marino else
5387e4b17023SJohn Marino storedi =
5388e4b17023SJohn Marino force_gimple_operand_gsi (&si,
5389e4b17023SJohn Marino build1 (VIEW_CONVERT_EXPR, itype,
5390e4b17023SJohn Marino stored_val), true, NULL_TREE, true,
5391e4b17023SJohn Marino GSI_SAME_STMT);
5392e4b17023SJohn Marino
5393e4b17023SJohn Marino /* Build the compare&swap statement. */
5394e4b17023SJohn Marino new_storedi = build_call_expr (cmpxchg, 3, iaddr, loadedi, storedi);
5395e4b17023SJohn Marino new_storedi = force_gimple_operand_gsi (&si,
5396e4b17023SJohn Marino fold_convert (TREE_TYPE (loadedi),
5397e4b17023SJohn Marino new_storedi),
5398e4b17023SJohn Marino true, NULL_TREE,
5399e4b17023SJohn Marino true, GSI_SAME_STMT);
5400e4b17023SJohn Marino
5401e4b17023SJohn Marino if (gimple_in_ssa_p (cfun))
5402e4b17023SJohn Marino old_vali = loadedi;
5403e4b17023SJohn Marino else
5404e4b17023SJohn Marino {
5405e4b17023SJohn Marino old_vali = create_tmp_var (TREE_TYPE (loadedi), NULL);
5406e4b17023SJohn Marino if (gimple_in_ssa_p (cfun))
5407e4b17023SJohn Marino add_referenced_var (old_vali);
5408e4b17023SJohn Marino stmt = gimple_build_assign (old_vali, loadedi);
5409e4b17023SJohn Marino gsi_insert_before (&si, stmt, GSI_SAME_STMT);
5410e4b17023SJohn Marino
5411e4b17023SJohn Marino stmt = gimple_build_assign (loadedi, new_storedi);
5412e4b17023SJohn Marino gsi_insert_before (&si, stmt, GSI_SAME_STMT);
5413e4b17023SJohn Marino }
5414e4b17023SJohn Marino
5415e4b17023SJohn Marino /* Note that we always perform the comparison as an integer, even for
5416e4b17023SJohn Marino floating point. This allows the atomic operation to properly
5417e4b17023SJohn Marino succeed even with NaNs and -0.0. */
5418e4b17023SJohn Marino stmt = gimple_build_cond_empty
5419e4b17023SJohn Marino (build2 (NE_EXPR, boolean_type_node,
5420e4b17023SJohn Marino new_storedi, old_vali));
5421e4b17023SJohn Marino gsi_insert_before (&si, stmt, GSI_SAME_STMT);
5422e4b17023SJohn Marino
5423e4b17023SJohn Marino /* Update cfg. */
5424e4b17023SJohn Marino e = single_succ_edge (store_bb);
5425e4b17023SJohn Marino e->flags &= ~EDGE_FALLTHRU;
5426e4b17023SJohn Marino e->flags |= EDGE_FALSE_VALUE;
5427e4b17023SJohn Marino
5428e4b17023SJohn Marino e = make_edge (store_bb, loop_header, EDGE_TRUE_VALUE);
5429e4b17023SJohn Marino
5430e4b17023SJohn Marino /* Copy the new value to loadedi (we already did that before the condition
5431e4b17023SJohn Marino if we are not in SSA). */
5432e4b17023SJohn Marino if (gimple_in_ssa_p (cfun))
5433e4b17023SJohn Marino {
5434e4b17023SJohn Marino phi = gimple_seq_first_stmt (phi_nodes (loop_header));
5435e4b17023SJohn Marino SET_USE (PHI_ARG_DEF_PTR_FROM_EDGE (phi, e), new_storedi);
5436e4b17023SJohn Marino }
5437e4b17023SJohn Marino
5438e4b17023SJohn Marino /* Remove GIMPLE_OMP_ATOMIC_STORE. */
5439e4b17023SJohn Marino gsi_remove (&si, true);
5440e4b17023SJohn Marino
5441e4b17023SJohn Marino if (gimple_in_ssa_p (cfun))
5442e4b17023SJohn Marino update_ssa (TODO_update_ssa_no_phi);
5443e4b17023SJohn Marino
5444e4b17023SJohn Marino return true;
5445e4b17023SJohn Marino }
5446e4b17023SJohn Marino
5447e4b17023SJohn Marino /* A subroutine of expand_omp_atomic. Implement the atomic operation as:
5448e4b17023SJohn Marino
5449e4b17023SJohn Marino GOMP_atomic_start ();
5450e4b17023SJohn Marino *addr = rhs;
5451e4b17023SJohn Marino GOMP_atomic_end ();
5452e4b17023SJohn Marino
5453e4b17023SJohn Marino The result is not globally atomic, but works so long as all parallel
5454e4b17023SJohn Marino references are within #pragma omp atomic directives. According to
5455e4b17023SJohn Marino responses received from omp@openmp.org, appears to be within spec.
5456e4b17023SJohn Marino Which makes sense, since that's how several other compilers handle
5457e4b17023SJohn Marino this situation as well.
5458e4b17023SJohn Marino LOADED_VAL and ADDR are the operands of GIMPLE_OMP_ATOMIC_LOAD we're
5459e4b17023SJohn Marino expanding. STORED_VAL is the operand of the matching
5460e4b17023SJohn Marino GIMPLE_OMP_ATOMIC_STORE.
5461e4b17023SJohn Marino
5462e4b17023SJohn Marino We replace
5463e4b17023SJohn Marino GIMPLE_OMP_ATOMIC_LOAD (loaded_val, addr) with
5464e4b17023SJohn Marino loaded_val = *addr;
5465e4b17023SJohn Marino
5466e4b17023SJohn Marino and replace
5467e4b17023SJohn Marino GIMPLE_OMP_ATOMIC_STORE (stored_val) with
5468e4b17023SJohn Marino *addr = stored_val;
5469e4b17023SJohn Marino */
5470e4b17023SJohn Marino
5471e4b17023SJohn Marino static bool
expand_omp_atomic_mutex(basic_block load_bb,basic_block store_bb,tree addr,tree loaded_val,tree stored_val)5472e4b17023SJohn Marino expand_omp_atomic_mutex (basic_block load_bb, basic_block store_bb,
5473e4b17023SJohn Marino tree addr, tree loaded_val, tree stored_val)
5474e4b17023SJohn Marino {
5475e4b17023SJohn Marino gimple_stmt_iterator si;
5476e4b17023SJohn Marino gimple stmt;
5477e4b17023SJohn Marino tree t;
5478e4b17023SJohn Marino
5479e4b17023SJohn Marino si = gsi_last_bb (load_bb);
5480e4b17023SJohn Marino gcc_assert (gimple_code (gsi_stmt (si)) == GIMPLE_OMP_ATOMIC_LOAD);
5481e4b17023SJohn Marino
5482e4b17023SJohn Marino t = builtin_decl_explicit (BUILT_IN_GOMP_ATOMIC_START);
5483e4b17023SJohn Marino t = build_call_expr (t, 0);
5484e4b17023SJohn Marino force_gimple_operand_gsi (&si, t, true, NULL_TREE, true, GSI_SAME_STMT);
5485e4b17023SJohn Marino
5486e4b17023SJohn Marino stmt = gimple_build_assign (loaded_val, build_simple_mem_ref (addr));
5487e4b17023SJohn Marino gsi_insert_before (&si, stmt, GSI_SAME_STMT);
5488e4b17023SJohn Marino gsi_remove (&si, true);
5489e4b17023SJohn Marino
5490e4b17023SJohn Marino si = gsi_last_bb (store_bb);
5491e4b17023SJohn Marino gcc_assert (gimple_code (gsi_stmt (si)) == GIMPLE_OMP_ATOMIC_STORE);
5492e4b17023SJohn Marino
5493e4b17023SJohn Marino stmt = gimple_build_assign (build_simple_mem_ref (unshare_expr (addr)),
5494e4b17023SJohn Marino stored_val);
5495e4b17023SJohn Marino gsi_insert_before (&si, stmt, GSI_SAME_STMT);
5496e4b17023SJohn Marino
5497e4b17023SJohn Marino t = builtin_decl_explicit (BUILT_IN_GOMP_ATOMIC_END);
5498e4b17023SJohn Marino t = build_call_expr (t, 0);
5499e4b17023SJohn Marino force_gimple_operand_gsi (&si, t, true, NULL_TREE, true, GSI_SAME_STMT);
5500e4b17023SJohn Marino gsi_remove (&si, true);
5501e4b17023SJohn Marino
5502e4b17023SJohn Marino if (gimple_in_ssa_p (cfun))
5503e4b17023SJohn Marino update_ssa (TODO_update_ssa_no_phi);
5504e4b17023SJohn Marino return true;
5505e4b17023SJohn Marino }
5506e4b17023SJohn Marino
5507e4b17023SJohn Marino /* Expand an GIMPLE_OMP_ATOMIC statement. We try to expand
5508e4b17023SJohn Marino using expand_omp_atomic_fetch_op. If it failed, we try to
5509e4b17023SJohn Marino call expand_omp_atomic_pipeline, and if it fails too, the
5510e4b17023SJohn Marino ultimate fallback is wrapping the operation in a mutex
5511e4b17023SJohn Marino (expand_omp_atomic_mutex). REGION is the atomic region built
5512e4b17023SJohn Marino by build_omp_regions_1(). */
5513e4b17023SJohn Marino
5514e4b17023SJohn Marino static void
expand_omp_atomic(struct omp_region * region)5515e4b17023SJohn Marino expand_omp_atomic (struct omp_region *region)
5516e4b17023SJohn Marino {
5517e4b17023SJohn Marino basic_block load_bb = region->entry, store_bb = region->exit;
5518e4b17023SJohn Marino gimple load = last_stmt (load_bb), store = last_stmt (store_bb);
5519e4b17023SJohn Marino tree loaded_val = gimple_omp_atomic_load_lhs (load);
5520e4b17023SJohn Marino tree addr = gimple_omp_atomic_load_rhs (load);
5521e4b17023SJohn Marino tree stored_val = gimple_omp_atomic_store_val (store);
5522e4b17023SJohn Marino tree type = TYPE_MAIN_VARIANT (TREE_TYPE (TREE_TYPE (addr)));
5523e4b17023SJohn Marino HOST_WIDE_INT index;
5524e4b17023SJohn Marino
5525e4b17023SJohn Marino /* Make sure the type is one of the supported sizes. */
5526e4b17023SJohn Marino index = tree_low_cst (TYPE_SIZE_UNIT (type), 1);
5527e4b17023SJohn Marino index = exact_log2 (index);
5528e4b17023SJohn Marino if (index >= 0 && index <= 4)
5529e4b17023SJohn Marino {
5530e4b17023SJohn Marino unsigned int align = TYPE_ALIGN_UNIT (type);
5531e4b17023SJohn Marino
5532e4b17023SJohn Marino /* __sync builtins require strict data alignment. */
5533e4b17023SJohn Marino if (exact_log2 (align) >= index)
5534e4b17023SJohn Marino {
5535e4b17023SJohn Marino /* Atomic load. */
5536e4b17023SJohn Marino if (loaded_val == stored_val
5537e4b17023SJohn Marino && (GET_MODE_CLASS (TYPE_MODE (type)) == MODE_INT
5538e4b17023SJohn Marino || GET_MODE_CLASS (TYPE_MODE (type)) == MODE_FLOAT)
5539e4b17023SJohn Marino && GET_MODE_BITSIZE (TYPE_MODE (type)) <= BITS_PER_WORD
5540e4b17023SJohn Marino && expand_omp_atomic_load (load_bb, addr, loaded_val, index))
5541e4b17023SJohn Marino return;
5542e4b17023SJohn Marino
5543e4b17023SJohn Marino /* Atomic store. */
5544e4b17023SJohn Marino if ((GET_MODE_CLASS (TYPE_MODE (type)) == MODE_INT
5545e4b17023SJohn Marino || GET_MODE_CLASS (TYPE_MODE (type)) == MODE_FLOAT)
5546e4b17023SJohn Marino && GET_MODE_BITSIZE (TYPE_MODE (type)) <= BITS_PER_WORD
5547e4b17023SJohn Marino && store_bb == single_succ (load_bb)
5548e4b17023SJohn Marino && first_stmt (store_bb) == store
5549e4b17023SJohn Marino && expand_omp_atomic_store (load_bb, addr, loaded_val,
5550e4b17023SJohn Marino stored_val, index))
5551e4b17023SJohn Marino return;
5552e4b17023SJohn Marino
5553e4b17023SJohn Marino /* When possible, use specialized atomic update functions. */
5554e4b17023SJohn Marino if ((INTEGRAL_TYPE_P (type) || POINTER_TYPE_P (type))
5555e4b17023SJohn Marino && store_bb == single_succ (load_bb)
5556e4b17023SJohn Marino && expand_omp_atomic_fetch_op (load_bb, addr,
5557e4b17023SJohn Marino loaded_val, stored_val, index))
5558e4b17023SJohn Marino return;
5559e4b17023SJohn Marino
5560e4b17023SJohn Marino /* If we don't have specialized __sync builtins, try and implement
5561e4b17023SJohn Marino as a compare and swap loop. */
5562e4b17023SJohn Marino if (expand_omp_atomic_pipeline (load_bb, store_bb, addr,
5563e4b17023SJohn Marino loaded_val, stored_val, index))
5564e4b17023SJohn Marino return;
5565e4b17023SJohn Marino }
5566e4b17023SJohn Marino }
5567e4b17023SJohn Marino
5568e4b17023SJohn Marino /* The ultimate fallback is wrapping the operation in a mutex. */
5569e4b17023SJohn Marino expand_omp_atomic_mutex (load_bb, store_bb, addr, loaded_val, stored_val);
5570e4b17023SJohn Marino }
5571e4b17023SJohn Marino
5572e4b17023SJohn Marino
5573e4b17023SJohn Marino /* Expand the parallel region tree rooted at REGION. Expansion
5574e4b17023SJohn Marino proceeds in depth-first order. Innermost regions are expanded
5575e4b17023SJohn Marino first. This way, parallel regions that require a new function to
5576e4b17023SJohn Marino be created (e.g., GIMPLE_OMP_PARALLEL) can be expanded without having any
5577e4b17023SJohn Marino internal dependencies in their body. */
5578e4b17023SJohn Marino
5579e4b17023SJohn Marino static void
expand_omp(struct omp_region * region)5580e4b17023SJohn Marino expand_omp (struct omp_region *region)
5581e4b17023SJohn Marino {
5582e4b17023SJohn Marino while (region)
5583e4b17023SJohn Marino {
5584e4b17023SJohn Marino location_t saved_location;
5585e4b17023SJohn Marino
5586e4b17023SJohn Marino /* First, determine whether this is a combined parallel+workshare
5587e4b17023SJohn Marino region. */
5588e4b17023SJohn Marino if (region->type == GIMPLE_OMP_PARALLEL)
5589e4b17023SJohn Marino determine_parallel_type (region);
5590e4b17023SJohn Marino
5591e4b17023SJohn Marino if (region->inner)
5592e4b17023SJohn Marino expand_omp (region->inner);
5593e4b17023SJohn Marino
5594e4b17023SJohn Marino saved_location = input_location;
5595e4b17023SJohn Marino if (gimple_has_location (last_stmt (region->entry)))
5596e4b17023SJohn Marino input_location = gimple_location (last_stmt (region->entry));
5597e4b17023SJohn Marino
5598e4b17023SJohn Marino switch (region->type)
5599e4b17023SJohn Marino {
5600e4b17023SJohn Marino case GIMPLE_OMP_PARALLEL:
5601e4b17023SJohn Marino case GIMPLE_OMP_TASK:
5602e4b17023SJohn Marino expand_omp_taskreg (region);
5603e4b17023SJohn Marino break;
5604e4b17023SJohn Marino
5605e4b17023SJohn Marino case GIMPLE_OMP_FOR:
5606e4b17023SJohn Marino expand_omp_for (region);
5607e4b17023SJohn Marino break;
5608e4b17023SJohn Marino
5609e4b17023SJohn Marino case GIMPLE_OMP_SECTIONS:
5610e4b17023SJohn Marino expand_omp_sections (region);
5611e4b17023SJohn Marino break;
5612e4b17023SJohn Marino
5613e4b17023SJohn Marino case GIMPLE_OMP_SECTION:
5614e4b17023SJohn Marino /* Individual omp sections are handled together with their
5615e4b17023SJohn Marino parent GIMPLE_OMP_SECTIONS region. */
5616e4b17023SJohn Marino break;
5617e4b17023SJohn Marino
5618e4b17023SJohn Marino case GIMPLE_OMP_SINGLE:
5619e4b17023SJohn Marino expand_omp_single (region);
5620e4b17023SJohn Marino break;
5621e4b17023SJohn Marino
5622e4b17023SJohn Marino case GIMPLE_OMP_MASTER:
5623e4b17023SJohn Marino case GIMPLE_OMP_ORDERED:
5624e4b17023SJohn Marino case GIMPLE_OMP_CRITICAL:
5625e4b17023SJohn Marino expand_omp_synch (region);
5626e4b17023SJohn Marino break;
5627e4b17023SJohn Marino
5628e4b17023SJohn Marino case GIMPLE_OMP_ATOMIC_LOAD:
5629e4b17023SJohn Marino expand_omp_atomic (region);
5630e4b17023SJohn Marino break;
5631e4b17023SJohn Marino
5632e4b17023SJohn Marino default:
5633e4b17023SJohn Marino gcc_unreachable ();
5634e4b17023SJohn Marino }
5635e4b17023SJohn Marino
5636e4b17023SJohn Marino input_location = saved_location;
5637e4b17023SJohn Marino region = region->next;
5638e4b17023SJohn Marino }
5639e4b17023SJohn Marino }
5640e4b17023SJohn Marino
5641e4b17023SJohn Marino
5642e4b17023SJohn Marino /* Helper for build_omp_regions. Scan the dominator tree starting at
5643e4b17023SJohn Marino block BB. PARENT is the region that contains BB. If SINGLE_TREE is
5644e4b17023SJohn Marino true, the function ends once a single tree is built (otherwise, whole
5645e4b17023SJohn Marino forest of OMP constructs may be built). */
5646e4b17023SJohn Marino
5647e4b17023SJohn Marino static void
build_omp_regions_1(basic_block bb,struct omp_region * parent,bool single_tree)5648e4b17023SJohn Marino build_omp_regions_1 (basic_block bb, struct omp_region *parent,
5649e4b17023SJohn Marino bool single_tree)
5650e4b17023SJohn Marino {
5651e4b17023SJohn Marino gimple_stmt_iterator gsi;
5652e4b17023SJohn Marino gimple stmt;
5653e4b17023SJohn Marino basic_block son;
5654e4b17023SJohn Marino
5655e4b17023SJohn Marino gsi = gsi_last_bb (bb);
5656e4b17023SJohn Marino if (!gsi_end_p (gsi) && is_gimple_omp (gsi_stmt (gsi)))
5657e4b17023SJohn Marino {
5658e4b17023SJohn Marino struct omp_region *region;
5659e4b17023SJohn Marino enum gimple_code code;
5660e4b17023SJohn Marino
5661e4b17023SJohn Marino stmt = gsi_stmt (gsi);
5662e4b17023SJohn Marino code = gimple_code (stmt);
5663e4b17023SJohn Marino if (code == GIMPLE_OMP_RETURN)
5664e4b17023SJohn Marino {
5665e4b17023SJohn Marino /* STMT is the return point out of region PARENT. Mark it
5666e4b17023SJohn Marino as the exit point and make PARENT the immediately
5667e4b17023SJohn Marino enclosing region. */
5668e4b17023SJohn Marino gcc_assert (parent);
5669e4b17023SJohn Marino region = parent;
5670e4b17023SJohn Marino region->exit = bb;
5671e4b17023SJohn Marino parent = parent->outer;
5672e4b17023SJohn Marino }
5673e4b17023SJohn Marino else if (code == GIMPLE_OMP_ATOMIC_STORE)
5674e4b17023SJohn Marino {
5675e4b17023SJohn Marino /* GIMPLE_OMP_ATOMIC_STORE is analoguous to
5676e4b17023SJohn Marino GIMPLE_OMP_RETURN, but matches with
5677e4b17023SJohn Marino GIMPLE_OMP_ATOMIC_LOAD. */
5678e4b17023SJohn Marino gcc_assert (parent);
5679e4b17023SJohn Marino gcc_assert (parent->type == GIMPLE_OMP_ATOMIC_LOAD);
5680e4b17023SJohn Marino region = parent;
5681e4b17023SJohn Marino region->exit = bb;
5682e4b17023SJohn Marino parent = parent->outer;
5683e4b17023SJohn Marino }
5684e4b17023SJohn Marino
5685e4b17023SJohn Marino else if (code == GIMPLE_OMP_CONTINUE)
5686e4b17023SJohn Marino {
5687e4b17023SJohn Marino gcc_assert (parent);
5688e4b17023SJohn Marino parent->cont = bb;
5689e4b17023SJohn Marino }
5690e4b17023SJohn Marino else if (code == GIMPLE_OMP_SECTIONS_SWITCH)
5691e4b17023SJohn Marino {
5692e4b17023SJohn Marino /* GIMPLE_OMP_SECTIONS_SWITCH is part of
5693e4b17023SJohn Marino GIMPLE_OMP_SECTIONS, and we do nothing for it. */
5694e4b17023SJohn Marino ;
5695e4b17023SJohn Marino }
5696e4b17023SJohn Marino else
5697e4b17023SJohn Marino {
5698e4b17023SJohn Marino /* Otherwise, this directive becomes the parent for a new
5699e4b17023SJohn Marino region. */
5700e4b17023SJohn Marino region = new_omp_region (bb, code, parent);
5701e4b17023SJohn Marino parent = region;
5702e4b17023SJohn Marino }
5703e4b17023SJohn Marino }
5704e4b17023SJohn Marino
5705e4b17023SJohn Marino if (single_tree && !parent)
5706e4b17023SJohn Marino return;
5707e4b17023SJohn Marino
5708e4b17023SJohn Marino for (son = first_dom_son (CDI_DOMINATORS, bb);
5709e4b17023SJohn Marino son;
5710e4b17023SJohn Marino son = next_dom_son (CDI_DOMINATORS, son))
5711e4b17023SJohn Marino build_omp_regions_1 (son, parent, single_tree);
5712e4b17023SJohn Marino }
5713e4b17023SJohn Marino
5714e4b17023SJohn Marino /* Builds the tree of OMP regions rooted at ROOT, storing it to
5715e4b17023SJohn Marino root_omp_region. */
5716e4b17023SJohn Marino
5717e4b17023SJohn Marino static void
build_omp_regions_root(basic_block root)5718e4b17023SJohn Marino build_omp_regions_root (basic_block root)
5719e4b17023SJohn Marino {
5720e4b17023SJohn Marino gcc_assert (root_omp_region == NULL);
5721e4b17023SJohn Marino build_omp_regions_1 (root, NULL, true);
5722e4b17023SJohn Marino gcc_assert (root_omp_region != NULL);
5723e4b17023SJohn Marino }
5724e4b17023SJohn Marino
5725e4b17023SJohn Marino /* Expands omp construct (and its subconstructs) starting in HEAD. */
5726e4b17023SJohn Marino
5727e4b17023SJohn Marino void
omp_expand_local(basic_block head)5728e4b17023SJohn Marino omp_expand_local (basic_block head)
5729e4b17023SJohn Marino {
5730e4b17023SJohn Marino build_omp_regions_root (head);
5731e4b17023SJohn Marino if (dump_file && (dump_flags & TDF_DETAILS))
5732e4b17023SJohn Marino {
5733e4b17023SJohn Marino fprintf (dump_file, "\nOMP region tree\n\n");
5734e4b17023SJohn Marino dump_omp_region (dump_file, root_omp_region, 0);
5735e4b17023SJohn Marino fprintf (dump_file, "\n");
5736e4b17023SJohn Marino }
5737e4b17023SJohn Marino
5738e4b17023SJohn Marino remove_exit_barriers (root_omp_region);
5739e4b17023SJohn Marino expand_omp (root_omp_region);
5740e4b17023SJohn Marino
5741e4b17023SJohn Marino free_omp_regions ();
5742e4b17023SJohn Marino }
5743e4b17023SJohn Marino
5744e4b17023SJohn Marino /* Scan the CFG and build a tree of OMP regions. Return the root of
5745e4b17023SJohn Marino the OMP region tree. */
5746e4b17023SJohn Marino
5747e4b17023SJohn Marino static void
build_omp_regions(void)5748e4b17023SJohn Marino build_omp_regions (void)
5749e4b17023SJohn Marino {
5750e4b17023SJohn Marino gcc_assert (root_omp_region == NULL);
5751e4b17023SJohn Marino calculate_dominance_info (CDI_DOMINATORS);
5752e4b17023SJohn Marino build_omp_regions_1 (ENTRY_BLOCK_PTR, NULL, false);
5753e4b17023SJohn Marino }
5754e4b17023SJohn Marino
5755e4b17023SJohn Marino /* Main entry point for expanding OMP-GIMPLE into runtime calls. */
5756e4b17023SJohn Marino
5757e4b17023SJohn Marino static unsigned int
execute_expand_omp(void)5758e4b17023SJohn Marino execute_expand_omp (void)
5759e4b17023SJohn Marino {
5760e4b17023SJohn Marino build_omp_regions ();
5761e4b17023SJohn Marino
5762e4b17023SJohn Marino if (!root_omp_region)
5763e4b17023SJohn Marino return 0;
5764e4b17023SJohn Marino
5765e4b17023SJohn Marino if (dump_file)
5766e4b17023SJohn Marino {
5767e4b17023SJohn Marino fprintf (dump_file, "\nOMP region tree\n\n");
5768e4b17023SJohn Marino dump_omp_region (dump_file, root_omp_region, 0);
5769e4b17023SJohn Marino fprintf (dump_file, "\n");
5770e4b17023SJohn Marino }
5771e4b17023SJohn Marino
5772e4b17023SJohn Marino remove_exit_barriers (root_omp_region);
5773e4b17023SJohn Marino
5774e4b17023SJohn Marino expand_omp (root_omp_region);
5775e4b17023SJohn Marino
5776e4b17023SJohn Marino cleanup_tree_cfg ();
5777e4b17023SJohn Marino
5778e4b17023SJohn Marino free_omp_regions ();
5779e4b17023SJohn Marino
5780e4b17023SJohn Marino return 0;
5781e4b17023SJohn Marino }
5782e4b17023SJohn Marino
5783e4b17023SJohn Marino /* OMP expansion -- the default pass, run before creation of SSA form. */
5784e4b17023SJohn Marino
5785e4b17023SJohn Marino static bool
gate_expand_omp(void)5786e4b17023SJohn Marino gate_expand_omp (void)
5787e4b17023SJohn Marino {
5788e4b17023SJohn Marino return (flag_openmp != 0 && !seen_error ());
5789e4b17023SJohn Marino }
5790e4b17023SJohn Marino
5791e4b17023SJohn Marino struct gimple_opt_pass pass_expand_omp =
5792e4b17023SJohn Marino {
5793e4b17023SJohn Marino {
5794e4b17023SJohn Marino GIMPLE_PASS,
5795e4b17023SJohn Marino "ompexp", /* name */
5796e4b17023SJohn Marino gate_expand_omp, /* gate */
5797e4b17023SJohn Marino execute_expand_omp, /* execute */
5798e4b17023SJohn Marino NULL, /* sub */
5799e4b17023SJohn Marino NULL, /* next */
5800e4b17023SJohn Marino 0, /* static_pass_number */
5801e4b17023SJohn Marino TV_NONE, /* tv_id */
5802e4b17023SJohn Marino PROP_gimple_any, /* properties_required */
5803e4b17023SJohn Marino 0, /* properties_provided */
5804e4b17023SJohn Marino 0, /* properties_destroyed */
5805e4b17023SJohn Marino 0, /* todo_flags_start */
5806e4b17023SJohn Marino 0 /* todo_flags_finish */
5807e4b17023SJohn Marino }
5808e4b17023SJohn Marino };
5809e4b17023SJohn Marino
5810e4b17023SJohn Marino /* Routines to lower OpenMP directives into OMP-GIMPLE. */
5811e4b17023SJohn Marino
5812e4b17023SJohn Marino /* Lower the OpenMP sections directive in the current statement in GSI_P.
5813e4b17023SJohn Marino CTX is the enclosing OMP context for the current statement. */
5814e4b17023SJohn Marino
5815e4b17023SJohn Marino static void
lower_omp_sections(gimple_stmt_iterator * gsi_p,omp_context * ctx)5816e4b17023SJohn Marino lower_omp_sections (gimple_stmt_iterator *gsi_p, omp_context *ctx)
5817e4b17023SJohn Marino {
5818e4b17023SJohn Marino tree block, control;
5819e4b17023SJohn Marino gimple_stmt_iterator tgsi;
5820e4b17023SJohn Marino unsigned i, len;
5821e4b17023SJohn Marino gimple stmt, new_stmt, bind, t;
5822e4b17023SJohn Marino gimple_seq ilist, dlist, olist, new_body, body;
5823e4b17023SJohn Marino struct gimplify_ctx gctx;
5824e4b17023SJohn Marino
5825e4b17023SJohn Marino stmt = gsi_stmt (*gsi_p);
5826e4b17023SJohn Marino
5827e4b17023SJohn Marino push_gimplify_context (&gctx);
5828e4b17023SJohn Marino
5829e4b17023SJohn Marino dlist = NULL;
5830e4b17023SJohn Marino ilist = NULL;
5831e4b17023SJohn Marino lower_rec_input_clauses (gimple_omp_sections_clauses (stmt),
5832e4b17023SJohn Marino &ilist, &dlist, ctx);
5833e4b17023SJohn Marino
5834e4b17023SJohn Marino tgsi = gsi_start (gimple_omp_body (stmt));
5835e4b17023SJohn Marino for (len = 0; !gsi_end_p (tgsi); len++, gsi_next (&tgsi))
5836e4b17023SJohn Marino continue;
5837e4b17023SJohn Marino
5838e4b17023SJohn Marino tgsi = gsi_start (gimple_omp_body (stmt));
5839e4b17023SJohn Marino body = NULL;
5840e4b17023SJohn Marino for (i = 0; i < len; i++, gsi_next (&tgsi))
5841e4b17023SJohn Marino {
5842e4b17023SJohn Marino omp_context *sctx;
5843e4b17023SJohn Marino gimple sec_start;
5844e4b17023SJohn Marino
5845e4b17023SJohn Marino sec_start = gsi_stmt (tgsi);
5846e4b17023SJohn Marino sctx = maybe_lookup_ctx (sec_start);
5847e4b17023SJohn Marino gcc_assert (sctx);
5848e4b17023SJohn Marino
5849e4b17023SJohn Marino gimple_seq_add_stmt (&body, sec_start);
5850e4b17023SJohn Marino
5851e4b17023SJohn Marino lower_omp (gimple_omp_body (sec_start), sctx);
5852e4b17023SJohn Marino gimple_seq_add_seq (&body, gimple_omp_body (sec_start));
5853e4b17023SJohn Marino gimple_omp_set_body (sec_start, NULL);
5854e4b17023SJohn Marino
5855e4b17023SJohn Marino if (i == len - 1)
5856e4b17023SJohn Marino {
5857e4b17023SJohn Marino gimple_seq l = NULL;
5858e4b17023SJohn Marino lower_lastprivate_clauses (gimple_omp_sections_clauses (stmt), NULL,
5859e4b17023SJohn Marino &l, ctx);
5860e4b17023SJohn Marino gimple_seq_add_seq (&body, l);
5861e4b17023SJohn Marino gimple_omp_section_set_last (sec_start);
5862e4b17023SJohn Marino }
5863e4b17023SJohn Marino
5864e4b17023SJohn Marino gimple_seq_add_stmt (&body, gimple_build_omp_return (false));
5865e4b17023SJohn Marino }
5866e4b17023SJohn Marino
5867e4b17023SJohn Marino block = make_node (BLOCK);
5868e4b17023SJohn Marino bind = gimple_build_bind (NULL, body, block);
5869e4b17023SJohn Marino
5870e4b17023SJohn Marino olist = NULL;
5871e4b17023SJohn Marino lower_reduction_clauses (gimple_omp_sections_clauses (stmt), &olist, ctx);
5872e4b17023SJohn Marino
5873e4b17023SJohn Marino block = make_node (BLOCK);
5874e4b17023SJohn Marino new_stmt = gimple_build_bind (NULL, NULL, block);
5875e4b17023SJohn Marino
5876e4b17023SJohn Marino pop_gimplify_context (new_stmt);
5877e4b17023SJohn Marino gimple_bind_append_vars (new_stmt, ctx->block_vars);
5878e4b17023SJohn Marino BLOCK_VARS (block) = gimple_bind_vars (bind);
5879e4b17023SJohn Marino if (BLOCK_VARS (block))
5880e4b17023SJohn Marino TREE_USED (block) = 1;
5881e4b17023SJohn Marino
5882e4b17023SJohn Marino new_body = NULL;
5883e4b17023SJohn Marino gimple_seq_add_seq (&new_body, ilist);
5884e4b17023SJohn Marino gimple_seq_add_stmt (&new_body, stmt);
5885e4b17023SJohn Marino gimple_seq_add_stmt (&new_body, gimple_build_omp_sections_switch ());
5886e4b17023SJohn Marino gimple_seq_add_stmt (&new_body, bind);
5887e4b17023SJohn Marino
5888e4b17023SJohn Marino control = create_tmp_var (unsigned_type_node, ".section");
5889e4b17023SJohn Marino t = gimple_build_omp_continue (control, control);
5890e4b17023SJohn Marino gimple_omp_sections_set_control (stmt, control);
5891e4b17023SJohn Marino gimple_seq_add_stmt (&new_body, t);
5892e4b17023SJohn Marino
5893e4b17023SJohn Marino gimple_seq_add_seq (&new_body, olist);
5894e4b17023SJohn Marino gimple_seq_add_seq (&new_body, dlist);
5895e4b17023SJohn Marino
5896e4b17023SJohn Marino new_body = maybe_catch_exception (new_body);
5897e4b17023SJohn Marino
5898e4b17023SJohn Marino t = gimple_build_omp_return
5899e4b17023SJohn Marino (!!find_omp_clause (gimple_omp_sections_clauses (stmt),
5900e4b17023SJohn Marino OMP_CLAUSE_NOWAIT));
5901e4b17023SJohn Marino gimple_seq_add_stmt (&new_body, t);
5902e4b17023SJohn Marino
5903e4b17023SJohn Marino gimple_bind_set_body (new_stmt, new_body);
5904e4b17023SJohn Marino gimple_omp_set_body (stmt, NULL);
5905e4b17023SJohn Marino
5906e4b17023SJohn Marino gsi_replace (gsi_p, new_stmt, true);
5907e4b17023SJohn Marino }
5908e4b17023SJohn Marino
5909e4b17023SJohn Marino
5910e4b17023SJohn Marino /* A subroutine of lower_omp_single. Expand the simple form of
5911e4b17023SJohn Marino a GIMPLE_OMP_SINGLE, without a copyprivate clause:
5912e4b17023SJohn Marino
5913e4b17023SJohn Marino if (GOMP_single_start ())
5914e4b17023SJohn Marino BODY;
5915e4b17023SJohn Marino [ GOMP_barrier (); ] -> unless 'nowait' is present.
5916e4b17023SJohn Marino
5917e4b17023SJohn Marino FIXME. It may be better to delay expanding the logic of this until
5918e4b17023SJohn Marino pass_expand_omp. The expanded logic may make the job more difficult
5919e4b17023SJohn Marino to a synchronization analysis pass. */
5920e4b17023SJohn Marino
5921e4b17023SJohn Marino static void
lower_omp_single_simple(gimple single_stmt,gimple_seq * pre_p)5922e4b17023SJohn Marino lower_omp_single_simple (gimple single_stmt, gimple_seq *pre_p)
5923e4b17023SJohn Marino {
5924e4b17023SJohn Marino location_t loc = gimple_location (single_stmt);
5925e4b17023SJohn Marino tree tlabel = create_artificial_label (loc);
5926e4b17023SJohn Marino tree flabel = create_artificial_label (loc);
5927e4b17023SJohn Marino gimple call, cond;
5928e4b17023SJohn Marino tree lhs, decl;
5929e4b17023SJohn Marino
5930e4b17023SJohn Marino decl = builtin_decl_explicit (BUILT_IN_GOMP_SINGLE_START);
5931e4b17023SJohn Marino lhs = create_tmp_var (TREE_TYPE (TREE_TYPE (decl)), NULL);
5932e4b17023SJohn Marino call = gimple_build_call (decl, 0);
5933e4b17023SJohn Marino gimple_call_set_lhs (call, lhs);
5934e4b17023SJohn Marino gimple_seq_add_stmt (pre_p, call);
5935e4b17023SJohn Marino
5936e4b17023SJohn Marino cond = gimple_build_cond (EQ_EXPR, lhs,
5937e4b17023SJohn Marino fold_convert_loc (loc, TREE_TYPE (lhs),
5938e4b17023SJohn Marino boolean_true_node),
5939e4b17023SJohn Marino tlabel, flabel);
5940e4b17023SJohn Marino gimple_seq_add_stmt (pre_p, cond);
5941e4b17023SJohn Marino gimple_seq_add_stmt (pre_p, gimple_build_label (tlabel));
5942e4b17023SJohn Marino gimple_seq_add_seq (pre_p, gimple_omp_body (single_stmt));
5943e4b17023SJohn Marino gimple_seq_add_stmt (pre_p, gimple_build_label (flabel));
5944e4b17023SJohn Marino }
5945e4b17023SJohn Marino
5946e4b17023SJohn Marino
5947e4b17023SJohn Marino /* A subroutine of lower_omp_single. Expand the simple form of
5948e4b17023SJohn Marino a GIMPLE_OMP_SINGLE, with a copyprivate clause:
5949e4b17023SJohn Marino
5950e4b17023SJohn Marino #pragma omp single copyprivate (a, b, c)
5951e4b17023SJohn Marino
5952e4b17023SJohn Marino Create a new structure to hold copies of 'a', 'b' and 'c' and emit:
5953e4b17023SJohn Marino
5954e4b17023SJohn Marino {
5955e4b17023SJohn Marino if ((copyout_p = GOMP_single_copy_start ()) == NULL)
5956e4b17023SJohn Marino {
5957e4b17023SJohn Marino BODY;
5958e4b17023SJohn Marino copyout.a = a;
5959e4b17023SJohn Marino copyout.b = b;
5960e4b17023SJohn Marino copyout.c = c;
5961e4b17023SJohn Marino GOMP_single_copy_end (©out);
5962e4b17023SJohn Marino }
5963e4b17023SJohn Marino else
5964e4b17023SJohn Marino {
5965e4b17023SJohn Marino a = copyout_p->a;
5966e4b17023SJohn Marino b = copyout_p->b;
5967e4b17023SJohn Marino c = copyout_p->c;
5968e4b17023SJohn Marino }
5969e4b17023SJohn Marino GOMP_barrier ();
5970e4b17023SJohn Marino }
5971e4b17023SJohn Marino
5972e4b17023SJohn Marino FIXME. It may be better to delay expanding the logic of this until
5973e4b17023SJohn Marino pass_expand_omp. The expanded logic may make the job more difficult
5974e4b17023SJohn Marino to a synchronization analysis pass. */
5975e4b17023SJohn Marino
5976e4b17023SJohn Marino static void
lower_omp_single_copy(gimple single_stmt,gimple_seq * pre_p,omp_context * ctx)5977e4b17023SJohn Marino lower_omp_single_copy (gimple single_stmt, gimple_seq *pre_p, omp_context *ctx)
5978e4b17023SJohn Marino {
5979e4b17023SJohn Marino tree ptr_type, t, l0, l1, l2, bfn_decl;
5980e4b17023SJohn Marino gimple_seq copyin_seq;
5981e4b17023SJohn Marino location_t loc = gimple_location (single_stmt);
5982e4b17023SJohn Marino
5983e4b17023SJohn Marino ctx->sender_decl = create_tmp_var (ctx->record_type, ".omp_copy_o");
5984e4b17023SJohn Marino
5985e4b17023SJohn Marino ptr_type = build_pointer_type (ctx->record_type);
5986e4b17023SJohn Marino ctx->receiver_decl = create_tmp_var (ptr_type, ".omp_copy_i");
5987e4b17023SJohn Marino
5988e4b17023SJohn Marino l0 = create_artificial_label (loc);
5989e4b17023SJohn Marino l1 = create_artificial_label (loc);
5990e4b17023SJohn Marino l2 = create_artificial_label (loc);
5991e4b17023SJohn Marino
5992e4b17023SJohn Marino bfn_decl = builtin_decl_explicit (BUILT_IN_GOMP_SINGLE_COPY_START);
5993e4b17023SJohn Marino t = build_call_expr_loc (loc, bfn_decl, 0);
5994e4b17023SJohn Marino t = fold_convert_loc (loc, ptr_type, t);
5995e4b17023SJohn Marino gimplify_assign (ctx->receiver_decl, t, pre_p);
5996e4b17023SJohn Marino
5997e4b17023SJohn Marino t = build2 (EQ_EXPR, boolean_type_node, ctx->receiver_decl,
5998e4b17023SJohn Marino build_int_cst (ptr_type, 0));
5999e4b17023SJohn Marino t = build3 (COND_EXPR, void_type_node, t,
6000e4b17023SJohn Marino build_and_jump (&l0), build_and_jump (&l1));
6001e4b17023SJohn Marino gimplify_and_add (t, pre_p);
6002e4b17023SJohn Marino
6003e4b17023SJohn Marino gimple_seq_add_stmt (pre_p, gimple_build_label (l0));
6004e4b17023SJohn Marino
6005e4b17023SJohn Marino gimple_seq_add_seq (pre_p, gimple_omp_body (single_stmt));
6006e4b17023SJohn Marino
6007e4b17023SJohn Marino copyin_seq = NULL;
6008e4b17023SJohn Marino lower_copyprivate_clauses (gimple_omp_single_clauses (single_stmt), pre_p,
6009e4b17023SJohn Marino ©in_seq, ctx);
6010e4b17023SJohn Marino
6011e4b17023SJohn Marino t = build_fold_addr_expr_loc (loc, ctx->sender_decl);
6012e4b17023SJohn Marino bfn_decl = builtin_decl_explicit (BUILT_IN_GOMP_SINGLE_COPY_END);
6013e4b17023SJohn Marino t = build_call_expr_loc (loc, bfn_decl, 1, t);
6014e4b17023SJohn Marino gimplify_and_add (t, pre_p);
6015e4b17023SJohn Marino
6016e4b17023SJohn Marino t = build_and_jump (&l2);
6017e4b17023SJohn Marino gimplify_and_add (t, pre_p);
6018e4b17023SJohn Marino
6019e4b17023SJohn Marino gimple_seq_add_stmt (pre_p, gimple_build_label (l1));
6020e4b17023SJohn Marino
6021e4b17023SJohn Marino gimple_seq_add_seq (pre_p, copyin_seq);
6022e4b17023SJohn Marino
6023e4b17023SJohn Marino gimple_seq_add_stmt (pre_p, gimple_build_label (l2));
6024e4b17023SJohn Marino }
6025e4b17023SJohn Marino
6026e4b17023SJohn Marino
6027e4b17023SJohn Marino /* Expand code for an OpenMP single directive. */
6028e4b17023SJohn Marino
6029e4b17023SJohn Marino static void
lower_omp_single(gimple_stmt_iterator * gsi_p,omp_context * ctx)6030e4b17023SJohn Marino lower_omp_single (gimple_stmt_iterator *gsi_p, omp_context *ctx)
6031e4b17023SJohn Marino {
6032e4b17023SJohn Marino tree block;
6033e4b17023SJohn Marino gimple t, bind, single_stmt = gsi_stmt (*gsi_p);
6034e4b17023SJohn Marino gimple_seq bind_body, dlist;
6035e4b17023SJohn Marino struct gimplify_ctx gctx;
6036e4b17023SJohn Marino
6037e4b17023SJohn Marino push_gimplify_context (&gctx);
6038e4b17023SJohn Marino
6039e4b17023SJohn Marino bind_body = NULL;
6040e4b17023SJohn Marino lower_rec_input_clauses (gimple_omp_single_clauses (single_stmt),
6041e4b17023SJohn Marino &bind_body, &dlist, ctx);
6042e4b17023SJohn Marino lower_omp (gimple_omp_body (single_stmt), ctx);
6043e4b17023SJohn Marino
6044e4b17023SJohn Marino gimple_seq_add_stmt (&bind_body, single_stmt);
6045e4b17023SJohn Marino
6046e4b17023SJohn Marino if (ctx->record_type)
6047e4b17023SJohn Marino lower_omp_single_copy (single_stmt, &bind_body, ctx);
6048e4b17023SJohn Marino else
6049e4b17023SJohn Marino lower_omp_single_simple (single_stmt, &bind_body);
6050e4b17023SJohn Marino
6051e4b17023SJohn Marino gimple_omp_set_body (single_stmt, NULL);
6052e4b17023SJohn Marino
6053e4b17023SJohn Marino gimple_seq_add_seq (&bind_body, dlist);
6054e4b17023SJohn Marino
6055e4b17023SJohn Marino bind_body = maybe_catch_exception (bind_body);
6056e4b17023SJohn Marino
6057e4b17023SJohn Marino t = gimple_build_omp_return
6058e4b17023SJohn Marino (!!find_omp_clause (gimple_omp_single_clauses (single_stmt),
6059e4b17023SJohn Marino OMP_CLAUSE_NOWAIT));
6060e4b17023SJohn Marino gimple_seq_add_stmt (&bind_body, t);
6061e4b17023SJohn Marino
6062e4b17023SJohn Marino block = make_node (BLOCK);
6063e4b17023SJohn Marino bind = gimple_build_bind (NULL, bind_body, block);
6064e4b17023SJohn Marino
6065e4b17023SJohn Marino pop_gimplify_context (bind);
6066e4b17023SJohn Marino
6067e4b17023SJohn Marino gimple_bind_append_vars (bind, ctx->block_vars);
6068e4b17023SJohn Marino BLOCK_VARS (block) = ctx->block_vars;
6069e4b17023SJohn Marino gsi_replace (gsi_p, bind, true);
6070e4b17023SJohn Marino if (BLOCK_VARS (block))
6071e4b17023SJohn Marino TREE_USED (block) = 1;
6072e4b17023SJohn Marino }
6073e4b17023SJohn Marino
6074e4b17023SJohn Marino
6075e4b17023SJohn Marino /* Expand code for an OpenMP master directive. */
6076e4b17023SJohn Marino
6077e4b17023SJohn Marino static void
lower_omp_master(gimple_stmt_iterator * gsi_p,omp_context * ctx)6078e4b17023SJohn Marino lower_omp_master (gimple_stmt_iterator *gsi_p, omp_context *ctx)
6079e4b17023SJohn Marino {
6080e4b17023SJohn Marino tree block, lab = NULL, x, bfn_decl;
6081e4b17023SJohn Marino gimple stmt = gsi_stmt (*gsi_p), bind;
6082e4b17023SJohn Marino location_t loc = gimple_location (stmt);
6083e4b17023SJohn Marino gimple_seq tseq;
6084e4b17023SJohn Marino struct gimplify_ctx gctx;
6085e4b17023SJohn Marino
6086e4b17023SJohn Marino push_gimplify_context (&gctx);
6087e4b17023SJohn Marino
6088e4b17023SJohn Marino block = make_node (BLOCK);
6089e4b17023SJohn Marino bind = gimple_build_bind (NULL, gimple_seq_alloc_with_stmt (stmt),
6090e4b17023SJohn Marino block);
6091e4b17023SJohn Marino
6092e4b17023SJohn Marino bfn_decl = builtin_decl_explicit (BUILT_IN_OMP_GET_THREAD_NUM);
6093e4b17023SJohn Marino x = build_call_expr_loc (loc, bfn_decl, 0);
6094e4b17023SJohn Marino x = build2 (EQ_EXPR, boolean_type_node, x, integer_zero_node);
6095e4b17023SJohn Marino x = build3 (COND_EXPR, void_type_node, x, NULL, build_and_jump (&lab));
6096e4b17023SJohn Marino tseq = NULL;
6097e4b17023SJohn Marino gimplify_and_add (x, &tseq);
6098e4b17023SJohn Marino gimple_bind_add_seq (bind, tseq);
6099e4b17023SJohn Marino
6100e4b17023SJohn Marino lower_omp (gimple_omp_body (stmt), ctx);
6101e4b17023SJohn Marino gimple_omp_set_body (stmt, maybe_catch_exception (gimple_omp_body (stmt)));
6102e4b17023SJohn Marino gimple_bind_add_seq (bind, gimple_omp_body (stmt));
6103e4b17023SJohn Marino gimple_omp_set_body (stmt, NULL);
6104e4b17023SJohn Marino
6105e4b17023SJohn Marino gimple_bind_add_stmt (bind, gimple_build_label (lab));
6106e4b17023SJohn Marino
6107e4b17023SJohn Marino gimple_bind_add_stmt (bind, gimple_build_omp_return (true));
6108e4b17023SJohn Marino
6109e4b17023SJohn Marino pop_gimplify_context (bind);
6110e4b17023SJohn Marino
6111e4b17023SJohn Marino gimple_bind_append_vars (bind, ctx->block_vars);
6112e4b17023SJohn Marino BLOCK_VARS (block) = ctx->block_vars;
6113e4b17023SJohn Marino gsi_replace (gsi_p, bind, true);
6114e4b17023SJohn Marino }
6115e4b17023SJohn Marino
6116e4b17023SJohn Marino
6117e4b17023SJohn Marino /* Expand code for an OpenMP ordered directive. */
6118e4b17023SJohn Marino
6119e4b17023SJohn Marino static void
lower_omp_ordered(gimple_stmt_iterator * gsi_p,omp_context * ctx)6120e4b17023SJohn Marino lower_omp_ordered (gimple_stmt_iterator *gsi_p, omp_context *ctx)
6121e4b17023SJohn Marino {
6122e4b17023SJohn Marino tree block;
6123e4b17023SJohn Marino gimple stmt = gsi_stmt (*gsi_p), bind, x;
6124e4b17023SJohn Marino struct gimplify_ctx gctx;
6125e4b17023SJohn Marino
6126e4b17023SJohn Marino push_gimplify_context (&gctx);
6127e4b17023SJohn Marino
6128e4b17023SJohn Marino block = make_node (BLOCK);
6129e4b17023SJohn Marino bind = gimple_build_bind (NULL, gimple_seq_alloc_with_stmt (stmt),
6130e4b17023SJohn Marino block);
6131e4b17023SJohn Marino
6132e4b17023SJohn Marino x = gimple_build_call (builtin_decl_explicit (BUILT_IN_GOMP_ORDERED_START),
6133e4b17023SJohn Marino 0);
6134e4b17023SJohn Marino gimple_bind_add_stmt (bind, x);
6135e4b17023SJohn Marino
6136e4b17023SJohn Marino lower_omp (gimple_omp_body (stmt), ctx);
6137e4b17023SJohn Marino gimple_omp_set_body (stmt, maybe_catch_exception (gimple_omp_body (stmt)));
6138e4b17023SJohn Marino gimple_bind_add_seq (bind, gimple_omp_body (stmt));
6139e4b17023SJohn Marino gimple_omp_set_body (stmt, NULL);
6140e4b17023SJohn Marino
6141e4b17023SJohn Marino x = gimple_build_call (builtin_decl_explicit (BUILT_IN_GOMP_ORDERED_END), 0);
6142e4b17023SJohn Marino gimple_bind_add_stmt (bind, x);
6143e4b17023SJohn Marino
6144e4b17023SJohn Marino gimple_bind_add_stmt (bind, gimple_build_omp_return (true));
6145e4b17023SJohn Marino
6146e4b17023SJohn Marino pop_gimplify_context (bind);
6147e4b17023SJohn Marino
6148e4b17023SJohn Marino gimple_bind_append_vars (bind, ctx->block_vars);
6149e4b17023SJohn Marino BLOCK_VARS (block) = gimple_bind_vars (bind);
6150e4b17023SJohn Marino gsi_replace (gsi_p, bind, true);
6151e4b17023SJohn Marino }
6152e4b17023SJohn Marino
6153e4b17023SJohn Marino
6154e4b17023SJohn Marino /* Gimplify a GIMPLE_OMP_CRITICAL statement. This is a relatively simple
6155e4b17023SJohn Marino substitution of a couple of function calls. But in the NAMED case,
6156e4b17023SJohn Marino requires that languages coordinate a symbol name. It is therefore
6157e4b17023SJohn Marino best put here in common code. */
6158e4b17023SJohn Marino
6159e4b17023SJohn Marino static GTY((param1_is (tree), param2_is (tree)))
6160e4b17023SJohn Marino splay_tree critical_name_mutexes;
6161e4b17023SJohn Marino
6162e4b17023SJohn Marino static void
lower_omp_critical(gimple_stmt_iterator * gsi_p,omp_context * ctx)6163e4b17023SJohn Marino lower_omp_critical (gimple_stmt_iterator *gsi_p, omp_context *ctx)
6164e4b17023SJohn Marino {
6165e4b17023SJohn Marino tree block;
6166e4b17023SJohn Marino tree name, lock, unlock;
6167e4b17023SJohn Marino gimple stmt = gsi_stmt (*gsi_p), bind;
6168e4b17023SJohn Marino location_t loc = gimple_location (stmt);
6169e4b17023SJohn Marino gimple_seq tbody;
6170e4b17023SJohn Marino struct gimplify_ctx gctx;
6171e4b17023SJohn Marino
6172e4b17023SJohn Marino name = gimple_omp_critical_name (stmt);
6173e4b17023SJohn Marino if (name)
6174e4b17023SJohn Marino {
6175e4b17023SJohn Marino tree decl;
6176e4b17023SJohn Marino splay_tree_node n;
6177e4b17023SJohn Marino
6178e4b17023SJohn Marino if (!critical_name_mutexes)
6179e4b17023SJohn Marino critical_name_mutexes
6180e4b17023SJohn Marino = splay_tree_new_ggc (splay_tree_compare_pointers,
6181e4b17023SJohn Marino ggc_alloc_splay_tree_tree_node_tree_node_splay_tree_s,
6182e4b17023SJohn Marino ggc_alloc_splay_tree_tree_node_tree_node_splay_tree_node_s);
6183e4b17023SJohn Marino
6184e4b17023SJohn Marino n = splay_tree_lookup (critical_name_mutexes, (splay_tree_key) name);
6185e4b17023SJohn Marino if (n == NULL)
6186e4b17023SJohn Marino {
6187e4b17023SJohn Marino char *new_str;
6188e4b17023SJohn Marino
6189e4b17023SJohn Marino decl = create_tmp_var_raw (ptr_type_node, NULL);
6190e4b17023SJohn Marino
6191e4b17023SJohn Marino new_str = ACONCAT ((".gomp_critical_user_",
6192e4b17023SJohn Marino IDENTIFIER_POINTER (name), NULL));
6193e4b17023SJohn Marino DECL_NAME (decl) = get_identifier (new_str);
6194e4b17023SJohn Marino TREE_PUBLIC (decl) = 1;
6195e4b17023SJohn Marino TREE_STATIC (decl) = 1;
6196e4b17023SJohn Marino DECL_COMMON (decl) = 1;
6197e4b17023SJohn Marino DECL_ARTIFICIAL (decl) = 1;
6198e4b17023SJohn Marino DECL_IGNORED_P (decl) = 1;
6199e4b17023SJohn Marino varpool_finalize_decl (decl);
6200e4b17023SJohn Marino
6201e4b17023SJohn Marino splay_tree_insert (critical_name_mutexes, (splay_tree_key) name,
6202e4b17023SJohn Marino (splay_tree_value) decl);
6203e4b17023SJohn Marino }
6204e4b17023SJohn Marino else
6205e4b17023SJohn Marino decl = (tree) n->value;
6206e4b17023SJohn Marino
6207e4b17023SJohn Marino lock = builtin_decl_explicit (BUILT_IN_GOMP_CRITICAL_NAME_START);
6208e4b17023SJohn Marino lock = build_call_expr_loc (loc, lock, 1, build_fold_addr_expr_loc (loc, decl));
6209e4b17023SJohn Marino
6210e4b17023SJohn Marino unlock = builtin_decl_explicit (BUILT_IN_GOMP_CRITICAL_NAME_END);
6211e4b17023SJohn Marino unlock = build_call_expr_loc (loc, unlock, 1,
6212e4b17023SJohn Marino build_fold_addr_expr_loc (loc, decl));
6213e4b17023SJohn Marino }
6214e4b17023SJohn Marino else
6215e4b17023SJohn Marino {
6216e4b17023SJohn Marino lock = builtin_decl_explicit (BUILT_IN_GOMP_CRITICAL_START);
6217e4b17023SJohn Marino lock = build_call_expr_loc (loc, lock, 0);
6218e4b17023SJohn Marino
6219e4b17023SJohn Marino unlock = builtin_decl_explicit (BUILT_IN_GOMP_CRITICAL_END);
6220e4b17023SJohn Marino unlock = build_call_expr_loc (loc, unlock, 0);
6221e4b17023SJohn Marino }
6222e4b17023SJohn Marino
6223e4b17023SJohn Marino push_gimplify_context (&gctx);
6224e4b17023SJohn Marino
6225e4b17023SJohn Marino block = make_node (BLOCK);
6226e4b17023SJohn Marino bind = gimple_build_bind (NULL, gimple_seq_alloc_with_stmt (stmt), block);
6227e4b17023SJohn Marino
6228e4b17023SJohn Marino tbody = gimple_bind_body (bind);
6229e4b17023SJohn Marino gimplify_and_add (lock, &tbody);
6230e4b17023SJohn Marino gimple_bind_set_body (bind, tbody);
6231e4b17023SJohn Marino
6232e4b17023SJohn Marino lower_omp (gimple_omp_body (stmt), ctx);
6233e4b17023SJohn Marino gimple_omp_set_body (stmt, maybe_catch_exception (gimple_omp_body (stmt)));
6234e4b17023SJohn Marino gimple_bind_add_seq (bind, gimple_omp_body (stmt));
6235e4b17023SJohn Marino gimple_omp_set_body (stmt, NULL);
6236e4b17023SJohn Marino
6237e4b17023SJohn Marino tbody = gimple_bind_body (bind);
6238e4b17023SJohn Marino gimplify_and_add (unlock, &tbody);
6239e4b17023SJohn Marino gimple_bind_set_body (bind, tbody);
6240e4b17023SJohn Marino
6241e4b17023SJohn Marino gimple_bind_add_stmt (bind, gimple_build_omp_return (true));
6242e4b17023SJohn Marino
6243e4b17023SJohn Marino pop_gimplify_context (bind);
6244e4b17023SJohn Marino gimple_bind_append_vars (bind, ctx->block_vars);
6245e4b17023SJohn Marino BLOCK_VARS (block) = gimple_bind_vars (bind);
6246e4b17023SJohn Marino gsi_replace (gsi_p, bind, true);
6247e4b17023SJohn Marino }
6248e4b17023SJohn Marino
6249e4b17023SJohn Marino
6250e4b17023SJohn Marino /* A subroutine of lower_omp_for. Generate code to emit the predicate
6251e4b17023SJohn Marino for a lastprivate clause. Given a loop control predicate of (V
6252e4b17023SJohn Marino cond N2), we gate the clause on (!(V cond N2)). The lowered form
6253e4b17023SJohn Marino is appended to *DLIST, iterator initialization is appended to
6254e4b17023SJohn Marino *BODY_P. */
6255e4b17023SJohn Marino
6256e4b17023SJohn Marino static void
lower_omp_for_lastprivate(struct omp_for_data * fd,gimple_seq * body_p,gimple_seq * dlist,struct omp_context * ctx)6257e4b17023SJohn Marino lower_omp_for_lastprivate (struct omp_for_data *fd, gimple_seq *body_p,
6258e4b17023SJohn Marino gimple_seq *dlist, struct omp_context *ctx)
6259e4b17023SJohn Marino {
6260e4b17023SJohn Marino tree clauses, cond, vinit;
6261e4b17023SJohn Marino enum tree_code cond_code;
6262e4b17023SJohn Marino gimple_seq stmts;
6263e4b17023SJohn Marino
6264e4b17023SJohn Marino cond_code = fd->loop.cond_code;
6265e4b17023SJohn Marino cond_code = cond_code == LT_EXPR ? GE_EXPR : LE_EXPR;
6266e4b17023SJohn Marino
6267e4b17023SJohn Marino /* When possible, use a strict equality expression. This can let VRP
6268e4b17023SJohn Marino type optimizations deduce the value and remove a copy. */
6269e4b17023SJohn Marino if (host_integerp (fd->loop.step, 0))
6270e4b17023SJohn Marino {
6271e4b17023SJohn Marino HOST_WIDE_INT step = TREE_INT_CST_LOW (fd->loop.step);
6272e4b17023SJohn Marino if (step == 1 || step == -1)
6273e4b17023SJohn Marino cond_code = EQ_EXPR;
6274e4b17023SJohn Marino }
6275e4b17023SJohn Marino
6276e4b17023SJohn Marino cond = build2 (cond_code, boolean_type_node, fd->loop.v, fd->loop.n2);
6277e4b17023SJohn Marino
6278e4b17023SJohn Marino clauses = gimple_omp_for_clauses (fd->for_stmt);
6279e4b17023SJohn Marino stmts = NULL;
6280e4b17023SJohn Marino lower_lastprivate_clauses (clauses, cond, &stmts, ctx);
6281e4b17023SJohn Marino if (!gimple_seq_empty_p (stmts))
6282e4b17023SJohn Marino {
6283e4b17023SJohn Marino gimple_seq_add_seq (&stmts, *dlist);
6284e4b17023SJohn Marino *dlist = stmts;
6285e4b17023SJohn Marino
6286e4b17023SJohn Marino /* Optimize: v = 0; is usually cheaper than v = some_other_constant. */
6287e4b17023SJohn Marino vinit = fd->loop.n1;
6288e4b17023SJohn Marino if (cond_code == EQ_EXPR
6289e4b17023SJohn Marino && host_integerp (fd->loop.n2, 0)
6290e4b17023SJohn Marino && ! integer_zerop (fd->loop.n2))
6291e4b17023SJohn Marino vinit = build_int_cst (TREE_TYPE (fd->loop.v), 0);
6292e4b17023SJohn Marino
6293e4b17023SJohn Marino /* Initialize the iterator variable, so that threads that don't execute
6294e4b17023SJohn Marino any iterations don't execute the lastprivate clauses by accident. */
6295e4b17023SJohn Marino gimplify_assign (fd->loop.v, vinit, body_p);
6296e4b17023SJohn Marino }
6297e4b17023SJohn Marino }
6298e4b17023SJohn Marino
6299e4b17023SJohn Marino
6300e4b17023SJohn Marino /* Lower code for an OpenMP loop directive. */
6301e4b17023SJohn Marino
6302e4b17023SJohn Marino static void
lower_omp_for(gimple_stmt_iterator * gsi_p,omp_context * ctx)6303e4b17023SJohn Marino lower_omp_for (gimple_stmt_iterator *gsi_p, omp_context *ctx)
6304e4b17023SJohn Marino {
6305e4b17023SJohn Marino tree *rhs_p, block;
6306e4b17023SJohn Marino struct omp_for_data fd;
6307e4b17023SJohn Marino gimple stmt = gsi_stmt (*gsi_p), new_stmt;
6308e4b17023SJohn Marino gimple_seq omp_for_body, body, dlist;
6309e4b17023SJohn Marino size_t i;
6310e4b17023SJohn Marino struct gimplify_ctx gctx;
6311e4b17023SJohn Marino
6312e4b17023SJohn Marino push_gimplify_context (&gctx);
6313e4b17023SJohn Marino
6314e4b17023SJohn Marino lower_omp (gimple_omp_for_pre_body (stmt), ctx);
6315e4b17023SJohn Marino lower_omp (gimple_omp_body (stmt), ctx);
6316e4b17023SJohn Marino
6317e4b17023SJohn Marino block = make_node (BLOCK);
6318e4b17023SJohn Marino new_stmt = gimple_build_bind (NULL, NULL, block);
6319e4b17023SJohn Marino
6320e4b17023SJohn Marino /* Move declaration of temporaries in the loop body before we make
6321e4b17023SJohn Marino it go away. */
6322e4b17023SJohn Marino omp_for_body = gimple_omp_body (stmt);
6323e4b17023SJohn Marino if (!gimple_seq_empty_p (omp_for_body)
6324e4b17023SJohn Marino && gimple_code (gimple_seq_first_stmt (omp_for_body)) == GIMPLE_BIND)
6325e4b17023SJohn Marino {
6326e4b17023SJohn Marino tree vars = gimple_bind_vars (gimple_seq_first_stmt (omp_for_body));
6327e4b17023SJohn Marino gimple_bind_append_vars (new_stmt, vars);
6328e4b17023SJohn Marino }
6329e4b17023SJohn Marino
6330e4b17023SJohn Marino /* The pre-body and input clauses go before the lowered GIMPLE_OMP_FOR. */
6331e4b17023SJohn Marino dlist = NULL;
6332e4b17023SJohn Marino body = NULL;
6333e4b17023SJohn Marino lower_rec_input_clauses (gimple_omp_for_clauses (stmt), &body, &dlist, ctx);
6334e4b17023SJohn Marino gimple_seq_add_seq (&body, gimple_omp_for_pre_body (stmt));
6335e4b17023SJohn Marino
6336e4b17023SJohn Marino /* Lower the header expressions. At this point, we can assume that
6337e4b17023SJohn Marino the header is of the form:
6338e4b17023SJohn Marino
6339e4b17023SJohn Marino #pragma omp for (V = VAL1; V {<|>|<=|>=} VAL2; V = V [+-] VAL3)
6340e4b17023SJohn Marino
6341e4b17023SJohn Marino We just need to make sure that VAL1, VAL2 and VAL3 are lowered
6342e4b17023SJohn Marino using the .omp_data_s mapping, if needed. */
6343e4b17023SJohn Marino for (i = 0; i < gimple_omp_for_collapse (stmt); i++)
6344e4b17023SJohn Marino {
6345e4b17023SJohn Marino rhs_p = gimple_omp_for_initial_ptr (stmt, i);
6346e4b17023SJohn Marino if (!is_gimple_min_invariant (*rhs_p))
6347e4b17023SJohn Marino *rhs_p = get_formal_tmp_var (*rhs_p, &body);
6348e4b17023SJohn Marino
6349e4b17023SJohn Marino rhs_p = gimple_omp_for_final_ptr (stmt, i);
6350e4b17023SJohn Marino if (!is_gimple_min_invariant (*rhs_p))
6351e4b17023SJohn Marino *rhs_p = get_formal_tmp_var (*rhs_p, &body);
6352e4b17023SJohn Marino
6353e4b17023SJohn Marino rhs_p = &TREE_OPERAND (gimple_omp_for_incr (stmt, i), 1);
6354e4b17023SJohn Marino if (!is_gimple_min_invariant (*rhs_p))
6355e4b17023SJohn Marino *rhs_p = get_formal_tmp_var (*rhs_p, &body);
6356e4b17023SJohn Marino }
6357e4b17023SJohn Marino
6358e4b17023SJohn Marino /* Once lowered, extract the bounds and clauses. */
6359e4b17023SJohn Marino extract_omp_for_data (stmt, &fd, NULL);
6360e4b17023SJohn Marino
6361e4b17023SJohn Marino lower_omp_for_lastprivate (&fd, &body, &dlist, ctx);
6362e4b17023SJohn Marino
6363e4b17023SJohn Marino gimple_seq_add_stmt (&body, stmt);
6364e4b17023SJohn Marino gimple_seq_add_seq (&body, gimple_omp_body (stmt));
6365e4b17023SJohn Marino
6366e4b17023SJohn Marino gimple_seq_add_stmt (&body, gimple_build_omp_continue (fd.loop.v,
6367e4b17023SJohn Marino fd.loop.v));
6368e4b17023SJohn Marino
6369e4b17023SJohn Marino /* After the loop, add exit clauses. */
6370e4b17023SJohn Marino lower_reduction_clauses (gimple_omp_for_clauses (stmt), &body, ctx);
6371e4b17023SJohn Marino gimple_seq_add_seq (&body, dlist);
6372e4b17023SJohn Marino
6373e4b17023SJohn Marino body = maybe_catch_exception (body);
6374e4b17023SJohn Marino
6375e4b17023SJohn Marino /* Region exit marker goes at the end of the loop body. */
6376e4b17023SJohn Marino gimple_seq_add_stmt (&body, gimple_build_omp_return (fd.have_nowait));
6377e4b17023SJohn Marino
6378e4b17023SJohn Marino pop_gimplify_context (new_stmt);
6379e4b17023SJohn Marino
6380e4b17023SJohn Marino gimple_bind_append_vars (new_stmt, ctx->block_vars);
6381e4b17023SJohn Marino BLOCK_VARS (block) = gimple_bind_vars (new_stmt);
6382e4b17023SJohn Marino if (BLOCK_VARS (block))
6383e4b17023SJohn Marino TREE_USED (block) = 1;
6384e4b17023SJohn Marino
6385e4b17023SJohn Marino gimple_bind_set_body (new_stmt, body);
6386e4b17023SJohn Marino gimple_omp_set_body (stmt, NULL);
6387e4b17023SJohn Marino gimple_omp_for_set_pre_body (stmt, NULL);
6388e4b17023SJohn Marino gsi_replace (gsi_p, new_stmt, true);
6389e4b17023SJohn Marino }
6390e4b17023SJohn Marino
6391e4b17023SJohn Marino /* Callback for walk_stmts. Check if the current statement only contains
6392e4b17023SJohn Marino GIMPLE_OMP_FOR or GIMPLE_OMP_PARALLEL. */
6393e4b17023SJohn Marino
6394e4b17023SJohn Marino static tree
check_combined_parallel(gimple_stmt_iterator * gsi_p,bool * handled_ops_p,struct walk_stmt_info * wi)6395e4b17023SJohn Marino check_combined_parallel (gimple_stmt_iterator *gsi_p,
6396e4b17023SJohn Marino bool *handled_ops_p,
6397e4b17023SJohn Marino struct walk_stmt_info *wi)
6398e4b17023SJohn Marino {
6399e4b17023SJohn Marino int *info = (int *) wi->info;
6400e4b17023SJohn Marino gimple stmt = gsi_stmt (*gsi_p);
6401e4b17023SJohn Marino
6402e4b17023SJohn Marino *handled_ops_p = true;
6403e4b17023SJohn Marino switch (gimple_code (stmt))
6404e4b17023SJohn Marino {
6405e4b17023SJohn Marino WALK_SUBSTMTS;
6406e4b17023SJohn Marino
6407e4b17023SJohn Marino case GIMPLE_OMP_FOR:
6408e4b17023SJohn Marino case GIMPLE_OMP_SECTIONS:
6409e4b17023SJohn Marino *info = *info == 0 ? 1 : -1;
6410e4b17023SJohn Marino break;
6411e4b17023SJohn Marino default:
6412e4b17023SJohn Marino *info = -1;
6413e4b17023SJohn Marino break;
6414e4b17023SJohn Marino }
6415e4b17023SJohn Marino return NULL;
6416e4b17023SJohn Marino }
6417e4b17023SJohn Marino
6418e4b17023SJohn Marino struct omp_taskcopy_context
6419e4b17023SJohn Marino {
6420e4b17023SJohn Marino /* This field must be at the beginning, as we do "inheritance": Some
6421e4b17023SJohn Marino callback functions for tree-inline.c (e.g., omp_copy_decl)
6422e4b17023SJohn Marino receive a copy_body_data pointer that is up-casted to an
6423e4b17023SJohn Marino omp_context pointer. */
6424e4b17023SJohn Marino copy_body_data cb;
6425e4b17023SJohn Marino omp_context *ctx;
6426e4b17023SJohn Marino };
6427e4b17023SJohn Marino
6428e4b17023SJohn Marino static tree
task_copyfn_copy_decl(tree var,copy_body_data * cb)6429e4b17023SJohn Marino task_copyfn_copy_decl (tree var, copy_body_data *cb)
6430e4b17023SJohn Marino {
6431e4b17023SJohn Marino struct omp_taskcopy_context *tcctx = (struct omp_taskcopy_context *) cb;
6432e4b17023SJohn Marino
6433e4b17023SJohn Marino if (splay_tree_lookup (tcctx->ctx->sfield_map, (splay_tree_key) var))
6434e4b17023SJohn Marino return create_tmp_var (TREE_TYPE (var), NULL);
6435e4b17023SJohn Marino
6436e4b17023SJohn Marino return var;
6437e4b17023SJohn Marino }
6438e4b17023SJohn Marino
6439e4b17023SJohn Marino static tree
task_copyfn_remap_type(struct omp_taskcopy_context * tcctx,tree orig_type)6440e4b17023SJohn Marino task_copyfn_remap_type (struct omp_taskcopy_context *tcctx, tree orig_type)
6441e4b17023SJohn Marino {
6442e4b17023SJohn Marino tree name, new_fields = NULL, type, f;
6443e4b17023SJohn Marino
6444e4b17023SJohn Marino type = lang_hooks.types.make_type (RECORD_TYPE);
6445e4b17023SJohn Marino name = DECL_NAME (TYPE_NAME (orig_type));
6446e4b17023SJohn Marino name = build_decl (gimple_location (tcctx->ctx->stmt),
6447e4b17023SJohn Marino TYPE_DECL, name, type);
6448e4b17023SJohn Marino TYPE_NAME (type) = name;
6449e4b17023SJohn Marino
6450e4b17023SJohn Marino for (f = TYPE_FIELDS (orig_type); f ; f = TREE_CHAIN (f))
6451e4b17023SJohn Marino {
6452e4b17023SJohn Marino tree new_f = copy_node (f);
6453e4b17023SJohn Marino DECL_CONTEXT (new_f) = type;
6454e4b17023SJohn Marino TREE_TYPE (new_f) = remap_type (TREE_TYPE (f), &tcctx->cb);
6455e4b17023SJohn Marino TREE_CHAIN (new_f) = new_fields;
6456e4b17023SJohn Marino walk_tree (&DECL_SIZE (new_f), copy_tree_body_r, &tcctx->cb, NULL);
6457e4b17023SJohn Marino walk_tree (&DECL_SIZE_UNIT (new_f), copy_tree_body_r, &tcctx->cb, NULL);
6458e4b17023SJohn Marino walk_tree (&DECL_FIELD_OFFSET (new_f), copy_tree_body_r,
6459e4b17023SJohn Marino &tcctx->cb, NULL);
6460e4b17023SJohn Marino new_fields = new_f;
6461e4b17023SJohn Marino *pointer_map_insert (tcctx->cb.decl_map, f) = new_f;
6462e4b17023SJohn Marino }
6463e4b17023SJohn Marino TYPE_FIELDS (type) = nreverse (new_fields);
6464e4b17023SJohn Marino layout_type (type);
6465e4b17023SJohn Marino return type;
6466e4b17023SJohn Marino }
6467e4b17023SJohn Marino
6468e4b17023SJohn Marino /* Create task copyfn. */
6469e4b17023SJohn Marino
6470e4b17023SJohn Marino static void
create_task_copyfn(gimple task_stmt,omp_context * ctx)6471e4b17023SJohn Marino create_task_copyfn (gimple task_stmt, omp_context *ctx)
6472e4b17023SJohn Marino {
6473e4b17023SJohn Marino struct function *child_cfun;
6474e4b17023SJohn Marino tree child_fn, t, c, src, dst, f, sf, arg, sarg, decl;
6475e4b17023SJohn Marino tree record_type, srecord_type, bind, list;
6476e4b17023SJohn Marino bool record_needs_remap = false, srecord_needs_remap = false;
6477e4b17023SJohn Marino splay_tree_node n;
6478e4b17023SJohn Marino struct omp_taskcopy_context tcctx;
6479e4b17023SJohn Marino struct gimplify_ctx gctx;
6480e4b17023SJohn Marino location_t loc = gimple_location (task_stmt);
6481e4b17023SJohn Marino
6482e4b17023SJohn Marino child_fn = gimple_omp_task_copy_fn (task_stmt);
6483e4b17023SJohn Marino child_cfun = DECL_STRUCT_FUNCTION (child_fn);
6484e4b17023SJohn Marino gcc_assert (child_cfun->cfg == NULL);
6485e4b17023SJohn Marino DECL_SAVED_TREE (child_fn) = alloc_stmt_list ();
6486e4b17023SJohn Marino
6487e4b17023SJohn Marino /* Reset DECL_CONTEXT on function arguments. */
6488e4b17023SJohn Marino for (t = DECL_ARGUMENTS (child_fn); t; t = DECL_CHAIN (t))
6489e4b17023SJohn Marino DECL_CONTEXT (t) = child_fn;
6490e4b17023SJohn Marino
6491e4b17023SJohn Marino /* Populate the function. */
6492e4b17023SJohn Marino push_gimplify_context (&gctx);
6493e4b17023SJohn Marino current_function_decl = child_fn;
6494e4b17023SJohn Marino
6495e4b17023SJohn Marino bind = build3 (BIND_EXPR, void_type_node, NULL, NULL, NULL);
6496e4b17023SJohn Marino TREE_SIDE_EFFECTS (bind) = 1;
6497e4b17023SJohn Marino list = NULL;
6498e4b17023SJohn Marino DECL_SAVED_TREE (child_fn) = bind;
6499e4b17023SJohn Marino DECL_SOURCE_LOCATION (child_fn) = gimple_location (task_stmt);
6500e4b17023SJohn Marino
6501e4b17023SJohn Marino /* Remap src and dst argument types if needed. */
6502e4b17023SJohn Marino record_type = ctx->record_type;
6503e4b17023SJohn Marino srecord_type = ctx->srecord_type;
6504e4b17023SJohn Marino for (f = TYPE_FIELDS (record_type); f ; f = DECL_CHAIN (f))
6505e4b17023SJohn Marino if (variably_modified_type_p (TREE_TYPE (f), ctx->cb.src_fn))
6506e4b17023SJohn Marino {
6507e4b17023SJohn Marino record_needs_remap = true;
6508e4b17023SJohn Marino break;
6509e4b17023SJohn Marino }
6510e4b17023SJohn Marino for (f = TYPE_FIELDS (srecord_type); f ; f = DECL_CHAIN (f))
6511e4b17023SJohn Marino if (variably_modified_type_p (TREE_TYPE (f), ctx->cb.src_fn))
6512e4b17023SJohn Marino {
6513e4b17023SJohn Marino srecord_needs_remap = true;
6514e4b17023SJohn Marino break;
6515e4b17023SJohn Marino }
6516e4b17023SJohn Marino
6517e4b17023SJohn Marino if (record_needs_remap || srecord_needs_remap)
6518e4b17023SJohn Marino {
6519e4b17023SJohn Marino memset (&tcctx, '\0', sizeof (tcctx));
6520e4b17023SJohn Marino tcctx.cb.src_fn = ctx->cb.src_fn;
6521e4b17023SJohn Marino tcctx.cb.dst_fn = child_fn;
6522e4b17023SJohn Marino tcctx.cb.src_node = cgraph_get_node (tcctx.cb.src_fn);
6523e4b17023SJohn Marino gcc_checking_assert (tcctx.cb.src_node);
6524e4b17023SJohn Marino tcctx.cb.dst_node = tcctx.cb.src_node;
6525e4b17023SJohn Marino tcctx.cb.src_cfun = ctx->cb.src_cfun;
6526e4b17023SJohn Marino tcctx.cb.copy_decl = task_copyfn_copy_decl;
6527e4b17023SJohn Marino tcctx.cb.eh_lp_nr = 0;
6528e4b17023SJohn Marino tcctx.cb.transform_call_graph_edges = CB_CGE_MOVE;
6529e4b17023SJohn Marino tcctx.cb.decl_map = pointer_map_create ();
6530e4b17023SJohn Marino tcctx.ctx = ctx;
6531e4b17023SJohn Marino
6532e4b17023SJohn Marino if (record_needs_remap)
6533e4b17023SJohn Marino record_type = task_copyfn_remap_type (&tcctx, record_type);
6534e4b17023SJohn Marino if (srecord_needs_remap)
6535e4b17023SJohn Marino srecord_type = task_copyfn_remap_type (&tcctx, srecord_type);
6536e4b17023SJohn Marino }
6537e4b17023SJohn Marino else
6538e4b17023SJohn Marino tcctx.cb.decl_map = NULL;
6539e4b17023SJohn Marino
6540e4b17023SJohn Marino push_cfun (child_cfun);
6541e4b17023SJohn Marino
6542e4b17023SJohn Marino arg = DECL_ARGUMENTS (child_fn);
6543e4b17023SJohn Marino TREE_TYPE (arg) = build_pointer_type (record_type);
6544e4b17023SJohn Marino sarg = DECL_CHAIN (arg);
6545e4b17023SJohn Marino TREE_TYPE (sarg) = build_pointer_type (srecord_type);
6546e4b17023SJohn Marino
6547e4b17023SJohn Marino /* First pass: initialize temporaries used in record_type and srecord_type
6548e4b17023SJohn Marino sizes and field offsets. */
6549e4b17023SJohn Marino if (tcctx.cb.decl_map)
6550e4b17023SJohn Marino for (c = gimple_omp_task_clauses (task_stmt); c; c = OMP_CLAUSE_CHAIN (c))
6551e4b17023SJohn Marino if (OMP_CLAUSE_CODE (c) == OMP_CLAUSE_FIRSTPRIVATE)
6552e4b17023SJohn Marino {
6553e4b17023SJohn Marino tree *p;
6554e4b17023SJohn Marino
6555e4b17023SJohn Marino decl = OMP_CLAUSE_DECL (c);
6556e4b17023SJohn Marino p = (tree *) pointer_map_contains (tcctx.cb.decl_map, decl);
6557e4b17023SJohn Marino if (p == NULL)
6558e4b17023SJohn Marino continue;
6559e4b17023SJohn Marino n = splay_tree_lookup (ctx->sfield_map, (splay_tree_key) decl);
6560e4b17023SJohn Marino sf = (tree) n->value;
6561e4b17023SJohn Marino sf = *(tree *) pointer_map_contains (tcctx.cb.decl_map, sf);
6562e4b17023SJohn Marino src = build_simple_mem_ref_loc (loc, sarg);
6563e4b17023SJohn Marino src = omp_build_component_ref (src, sf);
6564e4b17023SJohn Marino t = build2 (MODIFY_EXPR, TREE_TYPE (*p), *p, src);
6565e4b17023SJohn Marino append_to_statement_list (t, &list);
6566e4b17023SJohn Marino }
6567e4b17023SJohn Marino
6568e4b17023SJohn Marino /* Second pass: copy shared var pointers and copy construct non-VLA
6569e4b17023SJohn Marino firstprivate vars. */
6570e4b17023SJohn Marino for (c = gimple_omp_task_clauses (task_stmt); c; c = OMP_CLAUSE_CHAIN (c))
6571e4b17023SJohn Marino switch (OMP_CLAUSE_CODE (c))
6572e4b17023SJohn Marino {
6573e4b17023SJohn Marino case OMP_CLAUSE_SHARED:
6574e4b17023SJohn Marino decl = OMP_CLAUSE_DECL (c);
6575e4b17023SJohn Marino n = splay_tree_lookup (ctx->field_map, (splay_tree_key) decl);
6576e4b17023SJohn Marino if (n == NULL)
6577e4b17023SJohn Marino break;
6578e4b17023SJohn Marino f = (tree) n->value;
6579e4b17023SJohn Marino if (tcctx.cb.decl_map)
6580e4b17023SJohn Marino f = *(tree *) pointer_map_contains (tcctx.cb.decl_map, f);
6581e4b17023SJohn Marino n = splay_tree_lookup (ctx->sfield_map, (splay_tree_key) decl);
6582e4b17023SJohn Marino sf = (tree) n->value;
6583e4b17023SJohn Marino if (tcctx.cb.decl_map)
6584e4b17023SJohn Marino sf = *(tree *) pointer_map_contains (tcctx.cb.decl_map, sf);
6585e4b17023SJohn Marino src = build_simple_mem_ref_loc (loc, sarg);
6586e4b17023SJohn Marino src = omp_build_component_ref (src, sf);
6587e4b17023SJohn Marino dst = build_simple_mem_ref_loc (loc, arg);
6588e4b17023SJohn Marino dst = omp_build_component_ref (dst, f);
6589e4b17023SJohn Marino t = build2 (MODIFY_EXPR, TREE_TYPE (dst), dst, src);
6590e4b17023SJohn Marino append_to_statement_list (t, &list);
6591e4b17023SJohn Marino break;
6592e4b17023SJohn Marino case OMP_CLAUSE_FIRSTPRIVATE:
6593e4b17023SJohn Marino decl = OMP_CLAUSE_DECL (c);
6594e4b17023SJohn Marino if (is_variable_sized (decl))
6595e4b17023SJohn Marino break;
6596e4b17023SJohn Marino n = splay_tree_lookup (ctx->field_map, (splay_tree_key) decl);
6597e4b17023SJohn Marino if (n == NULL)
6598e4b17023SJohn Marino break;
6599e4b17023SJohn Marino f = (tree) n->value;
6600e4b17023SJohn Marino if (tcctx.cb.decl_map)
6601e4b17023SJohn Marino f = *(tree *) pointer_map_contains (tcctx.cb.decl_map, f);
6602e4b17023SJohn Marino n = splay_tree_lookup (ctx->sfield_map, (splay_tree_key) decl);
6603e4b17023SJohn Marino if (n != NULL)
6604e4b17023SJohn Marino {
6605e4b17023SJohn Marino sf = (tree) n->value;
6606e4b17023SJohn Marino if (tcctx.cb.decl_map)
6607e4b17023SJohn Marino sf = *(tree *) pointer_map_contains (tcctx.cb.decl_map, sf);
6608e4b17023SJohn Marino src = build_simple_mem_ref_loc (loc, sarg);
6609e4b17023SJohn Marino src = omp_build_component_ref (src, sf);
6610e4b17023SJohn Marino if (use_pointer_for_field (decl, NULL) || is_reference (decl))
6611e4b17023SJohn Marino src = build_simple_mem_ref_loc (loc, src);
6612e4b17023SJohn Marino }
6613e4b17023SJohn Marino else
6614e4b17023SJohn Marino src = decl;
6615e4b17023SJohn Marino dst = build_simple_mem_ref_loc (loc, arg);
6616e4b17023SJohn Marino dst = omp_build_component_ref (dst, f);
6617e4b17023SJohn Marino t = lang_hooks.decls.omp_clause_copy_ctor (c, dst, src);
6618e4b17023SJohn Marino append_to_statement_list (t, &list);
6619e4b17023SJohn Marino break;
6620e4b17023SJohn Marino case OMP_CLAUSE_PRIVATE:
6621e4b17023SJohn Marino if (! OMP_CLAUSE_PRIVATE_OUTER_REF (c))
6622e4b17023SJohn Marino break;
6623e4b17023SJohn Marino decl = OMP_CLAUSE_DECL (c);
6624e4b17023SJohn Marino n = splay_tree_lookup (ctx->field_map, (splay_tree_key) decl);
6625e4b17023SJohn Marino f = (tree) n->value;
6626e4b17023SJohn Marino if (tcctx.cb.decl_map)
6627e4b17023SJohn Marino f = *(tree *) pointer_map_contains (tcctx.cb.decl_map, f);
6628e4b17023SJohn Marino n = splay_tree_lookup (ctx->sfield_map, (splay_tree_key) decl);
6629e4b17023SJohn Marino if (n != NULL)
6630e4b17023SJohn Marino {
6631e4b17023SJohn Marino sf = (tree) n->value;
6632e4b17023SJohn Marino if (tcctx.cb.decl_map)
6633e4b17023SJohn Marino sf = *(tree *) pointer_map_contains (tcctx.cb.decl_map, sf);
6634e4b17023SJohn Marino src = build_simple_mem_ref_loc (loc, sarg);
6635e4b17023SJohn Marino src = omp_build_component_ref (src, sf);
6636e4b17023SJohn Marino if (use_pointer_for_field (decl, NULL))
6637e4b17023SJohn Marino src = build_simple_mem_ref_loc (loc, src);
6638e4b17023SJohn Marino }
6639e4b17023SJohn Marino else
6640e4b17023SJohn Marino src = decl;
6641e4b17023SJohn Marino dst = build_simple_mem_ref_loc (loc, arg);
6642e4b17023SJohn Marino dst = omp_build_component_ref (dst, f);
6643e4b17023SJohn Marino t = build2 (MODIFY_EXPR, TREE_TYPE (dst), dst, src);
6644e4b17023SJohn Marino append_to_statement_list (t, &list);
6645e4b17023SJohn Marino break;
6646e4b17023SJohn Marino default:
6647e4b17023SJohn Marino break;
6648e4b17023SJohn Marino }
6649e4b17023SJohn Marino
6650e4b17023SJohn Marino /* Last pass: handle VLA firstprivates. */
6651e4b17023SJohn Marino if (tcctx.cb.decl_map)
6652e4b17023SJohn Marino for (c = gimple_omp_task_clauses (task_stmt); c; c = OMP_CLAUSE_CHAIN (c))
6653e4b17023SJohn Marino if (OMP_CLAUSE_CODE (c) == OMP_CLAUSE_FIRSTPRIVATE)
6654e4b17023SJohn Marino {
6655e4b17023SJohn Marino tree ind, ptr, df;
6656e4b17023SJohn Marino
6657e4b17023SJohn Marino decl = OMP_CLAUSE_DECL (c);
6658e4b17023SJohn Marino if (!is_variable_sized (decl))
6659e4b17023SJohn Marino continue;
6660e4b17023SJohn Marino n = splay_tree_lookup (ctx->field_map, (splay_tree_key) decl);
6661e4b17023SJohn Marino if (n == NULL)
6662e4b17023SJohn Marino continue;
6663e4b17023SJohn Marino f = (tree) n->value;
6664e4b17023SJohn Marino f = *(tree *) pointer_map_contains (tcctx.cb.decl_map, f);
6665e4b17023SJohn Marino gcc_assert (DECL_HAS_VALUE_EXPR_P (decl));
6666e4b17023SJohn Marino ind = DECL_VALUE_EXPR (decl);
6667e4b17023SJohn Marino gcc_assert (TREE_CODE (ind) == INDIRECT_REF);
6668e4b17023SJohn Marino gcc_assert (DECL_P (TREE_OPERAND (ind, 0)));
6669e4b17023SJohn Marino n = splay_tree_lookup (ctx->sfield_map,
6670e4b17023SJohn Marino (splay_tree_key) TREE_OPERAND (ind, 0));
6671e4b17023SJohn Marino sf = (tree) n->value;
6672e4b17023SJohn Marino sf = *(tree *) pointer_map_contains (tcctx.cb.decl_map, sf);
6673e4b17023SJohn Marino src = build_simple_mem_ref_loc (loc, sarg);
6674e4b17023SJohn Marino src = omp_build_component_ref (src, sf);
6675e4b17023SJohn Marino src = build_simple_mem_ref_loc (loc, src);
6676e4b17023SJohn Marino dst = build_simple_mem_ref_loc (loc, arg);
6677e4b17023SJohn Marino dst = omp_build_component_ref (dst, f);
6678e4b17023SJohn Marino t = lang_hooks.decls.omp_clause_copy_ctor (c, dst, src);
6679e4b17023SJohn Marino append_to_statement_list (t, &list);
6680e4b17023SJohn Marino n = splay_tree_lookup (ctx->field_map,
6681e4b17023SJohn Marino (splay_tree_key) TREE_OPERAND (ind, 0));
6682e4b17023SJohn Marino df = (tree) n->value;
6683e4b17023SJohn Marino df = *(tree *) pointer_map_contains (tcctx.cb.decl_map, df);
6684e4b17023SJohn Marino ptr = build_simple_mem_ref_loc (loc, arg);
6685e4b17023SJohn Marino ptr = omp_build_component_ref (ptr, df);
6686e4b17023SJohn Marino t = build2 (MODIFY_EXPR, TREE_TYPE (ptr), ptr,
6687e4b17023SJohn Marino build_fold_addr_expr_loc (loc, dst));
6688e4b17023SJohn Marino append_to_statement_list (t, &list);
6689e4b17023SJohn Marino }
6690e4b17023SJohn Marino
6691e4b17023SJohn Marino t = build1 (RETURN_EXPR, void_type_node, NULL);
6692e4b17023SJohn Marino append_to_statement_list (t, &list);
6693e4b17023SJohn Marino
6694e4b17023SJohn Marino if (tcctx.cb.decl_map)
6695e4b17023SJohn Marino pointer_map_destroy (tcctx.cb.decl_map);
6696e4b17023SJohn Marino pop_gimplify_context (NULL);
6697e4b17023SJohn Marino BIND_EXPR_BODY (bind) = list;
6698e4b17023SJohn Marino pop_cfun ();
6699e4b17023SJohn Marino current_function_decl = ctx->cb.src_fn;
6700e4b17023SJohn Marino }
6701e4b17023SJohn Marino
6702e4b17023SJohn Marino /* Lower the OpenMP parallel or task directive in the current statement
6703e4b17023SJohn Marino in GSI_P. CTX holds context information for the directive. */
6704e4b17023SJohn Marino
6705e4b17023SJohn Marino static void
lower_omp_taskreg(gimple_stmt_iterator * gsi_p,omp_context * ctx)6706e4b17023SJohn Marino lower_omp_taskreg (gimple_stmt_iterator *gsi_p, omp_context *ctx)
6707e4b17023SJohn Marino {
6708e4b17023SJohn Marino tree clauses;
6709e4b17023SJohn Marino tree child_fn, t;
6710e4b17023SJohn Marino gimple stmt = gsi_stmt (*gsi_p);
6711e4b17023SJohn Marino gimple par_bind, bind;
6712e4b17023SJohn Marino gimple_seq par_body, olist, ilist, par_olist, par_ilist, new_body;
6713e4b17023SJohn Marino struct gimplify_ctx gctx;
6714e4b17023SJohn Marino location_t loc = gimple_location (stmt);
6715e4b17023SJohn Marino
6716e4b17023SJohn Marino clauses = gimple_omp_taskreg_clauses (stmt);
6717e4b17023SJohn Marino par_bind = gimple_seq_first_stmt (gimple_omp_body (stmt));
6718e4b17023SJohn Marino par_body = gimple_bind_body (par_bind);
6719e4b17023SJohn Marino child_fn = ctx->cb.dst_fn;
6720e4b17023SJohn Marino if (gimple_code (stmt) == GIMPLE_OMP_PARALLEL
6721e4b17023SJohn Marino && !gimple_omp_parallel_combined_p (stmt))
6722e4b17023SJohn Marino {
6723e4b17023SJohn Marino struct walk_stmt_info wi;
6724e4b17023SJohn Marino int ws_num = 0;
6725e4b17023SJohn Marino
6726e4b17023SJohn Marino memset (&wi, 0, sizeof (wi));
6727e4b17023SJohn Marino wi.info = &ws_num;
6728e4b17023SJohn Marino wi.val_only = true;
6729e4b17023SJohn Marino walk_gimple_seq (par_body, check_combined_parallel, NULL, &wi);
6730e4b17023SJohn Marino if (ws_num == 1)
6731e4b17023SJohn Marino gimple_omp_parallel_set_combined_p (stmt, true);
6732e4b17023SJohn Marino }
6733e4b17023SJohn Marino if (ctx->srecord_type)
6734e4b17023SJohn Marino create_task_copyfn (stmt, ctx);
6735e4b17023SJohn Marino
6736e4b17023SJohn Marino push_gimplify_context (&gctx);
6737e4b17023SJohn Marino
6738e4b17023SJohn Marino par_olist = NULL;
6739e4b17023SJohn Marino par_ilist = NULL;
6740e4b17023SJohn Marino lower_rec_input_clauses (clauses, &par_ilist, &par_olist, ctx);
6741e4b17023SJohn Marino lower_omp (par_body, ctx);
6742e4b17023SJohn Marino if (gimple_code (stmt) == GIMPLE_OMP_PARALLEL)
6743e4b17023SJohn Marino lower_reduction_clauses (clauses, &par_olist, ctx);
6744e4b17023SJohn Marino
6745e4b17023SJohn Marino /* Declare all the variables created by mapping and the variables
6746e4b17023SJohn Marino declared in the scope of the parallel body. */
6747e4b17023SJohn Marino record_vars_into (ctx->block_vars, child_fn);
6748e4b17023SJohn Marino record_vars_into (gimple_bind_vars (par_bind), child_fn);
6749e4b17023SJohn Marino
6750e4b17023SJohn Marino if (ctx->record_type)
6751e4b17023SJohn Marino {
6752e4b17023SJohn Marino ctx->sender_decl
6753e4b17023SJohn Marino = create_tmp_var (ctx->srecord_type ? ctx->srecord_type
6754e4b17023SJohn Marino : ctx->record_type, ".omp_data_o");
6755e4b17023SJohn Marino DECL_NAMELESS (ctx->sender_decl) = 1;
6756e4b17023SJohn Marino TREE_ADDRESSABLE (ctx->sender_decl) = 1;
6757e4b17023SJohn Marino gimple_omp_taskreg_set_data_arg (stmt, ctx->sender_decl);
6758e4b17023SJohn Marino }
6759e4b17023SJohn Marino
6760e4b17023SJohn Marino olist = NULL;
6761e4b17023SJohn Marino ilist = NULL;
6762e4b17023SJohn Marino lower_send_clauses (clauses, &ilist, &olist, ctx);
6763e4b17023SJohn Marino lower_send_shared_vars (&ilist, &olist, ctx);
6764e4b17023SJohn Marino
6765e4b17023SJohn Marino /* Once all the expansions are done, sequence all the different
6766e4b17023SJohn Marino fragments inside gimple_omp_body. */
6767e4b17023SJohn Marino
6768e4b17023SJohn Marino new_body = NULL;
6769e4b17023SJohn Marino
6770e4b17023SJohn Marino if (ctx->record_type)
6771e4b17023SJohn Marino {
6772e4b17023SJohn Marino t = build_fold_addr_expr_loc (loc, ctx->sender_decl);
6773e4b17023SJohn Marino /* fixup_child_record_type might have changed receiver_decl's type. */
6774e4b17023SJohn Marino t = fold_convert_loc (loc, TREE_TYPE (ctx->receiver_decl), t);
6775e4b17023SJohn Marino gimple_seq_add_stmt (&new_body,
6776e4b17023SJohn Marino gimple_build_assign (ctx->receiver_decl, t));
6777e4b17023SJohn Marino }
6778e4b17023SJohn Marino
6779e4b17023SJohn Marino gimple_seq_add_seq (&new_body, par_ilist);
6780e4b17023SJohn Marino gimple_seq_add_seq (&new_body, par_body);
6781e4b17023SJohn Marino gimple_seq_add_seq (&new_body, par_olist);
6782e4b17023SJohn Marino new_body = maybe_catch_exception (new_body);
6783e4b17023SJohn Marino gimple_seq_add_stmt (&new_body, gimple_build_omp_return (false));
6784e4b17023SJohn Marino gimple_omp_set_body (stmt, new_body);
6785e4b17023SJohn Marino
6786e4b17023SJohn Marino bind = gimple_build_bind (NULL, NULL, gimple_bind_block (par_bind));
6787e4b17023SJohn Marino gimple_bind_add_stmt (bind, stmt);
6788e4b17023SJohn Marino if (ilist || olist)
6789e4b17023SJohn Marino {
6790e4b17023SJohn Marino gimple_seq_add_stmt (&ilist, bind);
6791e4b17023SJohn Marino gimple_seq_add_seq (&ilist, olist);
6792e4b17023SJohn Marino bind = gimple_build_bind (NULL, ilist, NULL);
6793e4b17023SJohn Marino }
6794e4b17023SJohn Marino
6795e4b17023SJohn Marino gsi_replace (gsi_p, bind, true);
6796e4b17023SJohn Marino
6797e4b17023SJohn Marino pop_gimplify_context (NULL);
6798e4b17023SJohn Marino }
6799e4b17023SJohn Marino
6800e4b17023SJohn Marino /* Callback for lower_omp_1. Return non-NULL if *tp needs to be
6801e4b17023SJohn Marino regimplified. If DATA is non-NULL, lower_omp_1 is outside
6802e4b17023SJohn Marino of OpenMP context, but with task_shared_vars set. */
6803e4b17023SJohn Marino
6804e4b17023SJohn Marino static tree
lower_omp_regimplify_p(tree * tp,int * walk_subtrees,void * data)6805e4b17023SJohn Marino lower_omp_regimplify_p (tree *tp, int *walk_subtrees,
6806e4b17023SJohn Marino void *data)
6807e4b17023SJohn Marino {
6808e4b17023SJohn Marino tree t = *tp;
6809e4b17023SJohn Marino
6810e4b17023SJohn Marino /* Any variable with DECL_VALUE_EXPR needs to be regimplified. */
6811e4b17023SJohn Marino if (TREE_CODE (t) == VAR_DECL && data == NULL && DECL_HAS_VALUE_EXPR_P (t))
6812e4b17023SJohn Marino return t;
6813e4b17023SJohn Marino
6814e4b17023SJohn Marino if (task_shared_vars
6815e4b17023SJohn Marino && DECL_P (t)
6816e4b17023SJohn Marino && bitmap_bit_p (task_shared_vars, DECL_UID (t)))
6817e4b17023SJohn Marino return t;
6818e4b17023SJohn Marino
6819e4b17023SJohn Marino /* If a global variable has been privatized, TREE_CONSTANT on
6820e4b17023SJohn Marino ADDR_EXPR might be wrong. */
6821e4b17023SJohn Marino if (data == NULL && TREE_CODE (t) == ADDR_EXPR)
6822e4b17023SJohn Marino recompute_tree_invariant_for_addr_expr (t);
6823e4b17023SJohn Marino
6824e4b17023SJohn Marino *walk_subtrees = !TYPE_P (t) && !DECL_P (t);
6825e4b17023SJohn Marino return NULL_TREE;
6826e4b17023SJohn Marino }
6827e4b17023SJohn Marino
6828e4b17023SJohn Marino static void
lower_omp_1(gimple_stmt_iterator * gsi_p,omp_context * ctx)6829e4b17023SJohn Marino lower_omp_1 (gimple_stmt_iterator *gsi_p, omp_context *ctx)
6830e4b17023SJohn Marino {
6831e4b17023SJohn Marino gimple stmt = gsi_stmt (*gsi_p);
6832e4b17023SJohn Marino struct walk_stmt_info wi;
6833e4b17023SJohn Marino
6834e4b17023SJohn Marino if (gimple_has_location (stmt))
6835e4b17023SJohn Marino input_location = gimple_location (stmt);
6836e4b17023SJohn Marino
6837e4b17023SJohn Marino if (task_shared_vars)
6838e4b17023SJohn Marino memset (&wi, '\0', sizeof (wi));
6839e4b17023SJohn Marino
6840e4b17023SJohn Marino /* If we have issued syntax errors, avoid doing any heavy lifting.
6841e4b17023SJohn Marino Just replace the OpenMP directives with a NOP to avoid
6842e4b17023SJohn Marino confusing RTL expansion. */
6843e4b17023SJohn Marino if (seen_error () && is_gimple_omp (stmt))
6844e4b17023SJohn Marino {
6845e4b17023SJohn Marino gsi_replace (gsi_p, gimple_build_nop (), true);
6846e4b17023SJohn Marino return;
6847e4b17023SJohn Marino }
6848e4b17023SJohn Marino
6849e4b17023SJohn Marino switch (gimple_code (stmt))
6850e4b17023SJohn Marino {
6851e4b17023SJohn Marino case GIMPLE_COND:
6852e4b17023SJohn Marino if ((ctx || task_shared_vars)
6853e4b17023SJohn Marino && (walk_tree (gimple_cond_lhs_ptr (stmt), lower_omp_regimplify_p,
6854e4b17023SJohn Marino ctx ? NULL : &wi, NULL)
6855e4b17023SJohn Marino || walk_tree (gimple_cond_rhs_ptr (stmt), lower_omp_regimplify_p,
6856e4b17023SJohn Marino ctx ? NULL : &wi, NULL)))
6857e4b17023SJohn Marino gimple_regimplify_operands (stmt, gsi_p);
6858e4b17023SJohn Marino break;
6859e4b17023SJohn Marino case GIMPLE_CATCH:
6860e4b17023SJohn Marino lower_omp (gimple_catch_handler (stmt), ctx);
6861e4b17023SJohn Marino break;
6862e4b17023SJohn Marino case GIMPLE_EH_FILTER:
6863e4b17023SJohn Marino lower_omp (gimple_eh_filter_failure (stmt), ctx);
6864e4b17023SJohn Marino break;
6865e4b17023SJohn Marino case GIMPLE_TRY:
6866e4b17023SJohn Marino lower_omp (gimple_try_eval (stmt), ctx);
6867e4b17023SJohn Marino lower_omp (gimple_try_cleanup (stmt), ctx);
6868e4b17023SJohn Marino break;
6869e4b17023SJohn Marino case GIMPLE_TRANSACTION:
6870e4b17023SJohn Marino lower_omp (gimple_transaction_body (stmt), ctx);
6871e4b17023SJohn Marino break;
6872e4b17023SJohn Marino case GIMPLE_BIND:
6873e4b17023SJohn Marino lower_omp (gimple_bind_body (stmt), ctx);
6874e4b17023SJohn Marino break;
6875e4b17023SJohn Marino case GIMPLE_OMP_PARALLEL:
6876e4b17023SJohn Marino case GIMPLE_OMP_TASK:
6877e4b17023SJohn Marino ctx = maybe_lookup_ctx (stmt);
6878e4b17023SJohn Marino lower_omp_taskreg (gsi_p, ctx);
6879e4b17023SJohn Marino break;
6880e4b17023SJohn Marino case GIMPLE_OMP_FOR:
6881e4b17023SJohn Marino ctx = maybe_lookup_ctx (stmt);
6882e4b17023SJohn Marino gcc_assert (ctx);
6883e4b17023SJohn Marino lower_omp_for (gsi_p, ctx);
6884e4b17023SJohn Marino break;
6885e4b17023SJohn Marino case GIMPLE_OMP_SECTIONS:
6886e4b17023SJohn Marino ctx = maybe_lookup_ctx (stmt);
6887e4b17023SJohn Marino gcc_assert (ctx);
6888e4b17023SJohn Marino lower_omp_sections (gsi_p, ctx);
6889e4b17023SJohn Marino break;
6890e4b17023SJohn Marino case GIMPLE_OMP_SINGLE:
6891e4b17023SJohn Marino ctx = maybe_lookup_ctx (stmt);
6892e4b17023SJohn Marino gcc_assert (ctx);
6893e4b17023SJohn Marino lower_omp_single (gsi_p, ctx);
6894e4b17023SJohn Marino break;
6895e4b17023SJohn Marino case GIMPLE_OMP_MASTER:
6896e4b17023SJohn Marino ctx = maybe_lookup_ctx (stmt);
6897e4b17023SJohn Marino gcc_assert (ctx);
6898e4b17023SJohn Marino lower_omp_master (gsi_p, ctx);
6899e4b17023SJohn Marino break;
6900e4b17023SJohn Marino case GIMPLE_OMP_ORDERED:
6901e4b17023SJohn Marino ctx = maybe_lookup_ctx (stmt);
6902e4b17023SJohn Marino gcc_assert (ctx);
6903e4b17023SJohn Marino lower_omp_ordered (gsi_p, ctx);
6904e4b17023SJohn Marino break;
6905e4b17023SJohn Marino case GIMPLE_OMP_CRITICAL:
6906e4b17023SJohn Marino ctx = maybe_lookup_ctx (stmt);
6907e4b17023SJohn Marino gcc_assert (ctx);
6908e4b17023SJohn Marino lower_omp_critical (gsi_p, ctx);
6909e4b17023SJohn Marino break;
6910e4b17023SJohn Marino case GIMPLE_OMP_ATOMIC_LOAD:
6911e4b17023SJohn Marino if ((ctx || task_shared_vars)
6912e4b17023SJohn Marino && walk_tree (gimple_omp_atomic_load_rhs_ptr (stmt),
6913e4b17023SJohn Marino lower_omp_regimplify_p, ctx ? NULL : &wi, NULL))
6914e4b17023SJohn Marino gimple_regimplify_operands (stmt, gsi_p);
6915e4b17023SJohn Marino break;
6916e4b17023SJohn Marino default:
6917e4b17023SJohn Marino if ((ctx || task_shared_vars)
6918e4b17023SJohn Marino && walk_gimple_op (stmt, lower_omp_regimplify_p,
6919e4b17023SJohn Marino ctx ? NULL : &wi))
6920e4b17023SJohn Marino gimple_regimplify_operands (stmt, gsi_p);
6921e4b17023SJohn Marino break;
6922e4b17023SJohn Marino }
6923e4b17023SJohn Marino }
6924e4b17023SJohn Marino
6925e4b17023SJohn Marino static void
lower_omp(gimple_seq body,omp_context * ctx)6926e4b17023SJohn Marino lower_omp (gimple_seq body, omp_context *ctx)
6927e4b17023SJohn Marino {
6928e4b17023SJohn Marino location_t saved_location = input_location;
6929e4b17023SJohn Marino gimple_stmt_iterator gsi = gsi_start (body);
6930e4b17023SJohn Marino for (gsi = gsi_start (body); !gsi_end_p (gsi); gsi_next (&gsi))
6931e4b17023SJohn Marino lower_omp_1 (&gsi, ctx);
6932e4b17023SJohn Marino input_location = saved_location;
6933e4b17023SJohn Marino }
6934e4b17023SJohn Marino
6935e4b17023SJohn Marino /* Main entry point. */
6936e4b17023SJohn Marino
6937e4b17023SJohn Marino static unsigned int
execute_lower_omp(void)6938e4b17023SJohn Marino execute_lower_omp (void)
6939e4b17023SJohn Marino {
6940e4b17023SJohn Marino gimple_seq body;
6941e4b17023SJohn Marino
6942e4b17023SJohn Marino /* This pass always runs, to provide PROP_gimple_lomp.
6943e4b17023SJohn Marino But there is nothing to do unless -fopenmp is given. */
6944e4b17023SJohn Marino if (flag_openmp == 0)
6945e4b17023SJohn Marino return 0;
6946e4b17023SJohn Marino
6947e4b17023SJohn Marino all_contexts = splay_tree_new (splay_tree_compare_pointers, 0,
6948e4b17023SJohn Marino delete_omp_context);
6949e4b17023SJohn Marino
6950e4b17023SJohn Marino body = gimple_body (current_function_decl);
6951e4b17023SJohn Marino scan_omp (body, NULL);
6952e4b17023SJohn Marino gcc_assert (taskreg_nesting_level == 0);
6953e4b17023SJohn Marino
6954e4b17023SJohn Marino if (all_contexts->root)
6955e4b17023SJohn Marino {
6956e4b17023SJohn Marino struct gimplify_ctx gctx;
6957e4b17023SJohn Marino
6958e4b17023SJohn Marino if (task_shared_vars)
6959e4b17023SJohn Marino push_gimplify_context (&gctx);
6960e4b17023SJohn Marino lower_omp (body, NULL);
6961e4b17023SJohn Marino if (task_shared_vars)
6962e4b17023SJohn Marino pop_gimplify_context (NULL);
6963e4b17023SJohn Marino }
6964e4b17023SJohn Marino
6965e4b17023SJohn Marino if (all_contexts)
6966e4b17023SJohn Marino {
6967e4b17023SJohn Marino splay_tree_delete (all_contexts);
6968e4b17023SJohn Marino all_contexts = NULL;
6969e4b17023SJohn Marino }
6970e4b17023SJohn Marino BITMAP_FREE (task_shared_vars);
6971e4b17023SJohn Marino return 0;
6972e4b17023SJohn Marino }
6973e4b17023SJohn Marino
6974e4b17023SJohn Marino struct gimple_opt_pass pass_lower_omp =
6975e4b17023SJohn Marino {
6976e4b17023SJohn Marino {
6977e4b17023SJohn Marino GIMPLE_PASS,
6978e4b17023SJohn Marino "omplower", /* name */
6979e4b17023SJohn Marino NULL, /* gate */
6980e4b17023SJohn Marino execute_lower_omp, /* execute */
6981e4b17023SJohn Marino NULL, /* sub */
6982e4b17023SJohn Marino NULL, /* next */
6983e4b17023SJohn Marino 0, /* static_pass_number */
6984e4b17023SJohn Marino TV_NONE, /* tv_id */
6985e4b17023SJohn Marino PROP_gimple_any, /* properties_required */
6986e4b17023SJohn Marino PROP_gimple_lomp, /* properties_provided */
6987e4b17023SJohn Marino 0, /* properties_destroyed */
6988e4b17023SJohn Marino 0, /* todo_flags_start */
6989e4b17023SJohn Marino 0 /* todo_flags_finish */
6990e4b17023SJohn Marino }
6991e4b17023SJohn Marino };
6992e4b17023SJohn Marino
6993e4b17023SJohn Marino /* The following is a utility to diagnose OpenMP structured block violations.
6994e4b17023SJohn Marino It is not part of the "omplower" pass, as that's invoked too late. It
6995e4b17023SJohn Marino should be invoked by the respective front ends after gimplification. */
6996e4b17023SJohn Marino
6997e4b17023SJohn Marino static splay_tree all_labels;
6998e4b17023SJohn Marino
6999e4b17023SJohn Marino /* Check for mismatched contexts and generate an error if needed. Return
7000e4b17023SJohn Marino true if an error is detected. */
7001e4b17023SJohn Marino
7002e4b17023SJohn Marino static bool
diagnose_sb_0(gimple_stmt_iterator * gsi_p,gimple branch_ctx,gimple label_ctx)7003e4b17023SJohn Marino diagnose_sb_0 (gimple_stmt_iterator *gsi_p,
7004e4b17023SJohn Marino gimple branch_ctx, gimple label_ctx)
7005e4b17023SJohn Marino {
7006e4b17023SJohn Marino if (label_ctx == branch_ctx)
7007e4b17023SJohn Marino return false;
7008e4b17023SJohn Marino
7009e4b17023SJohn Marino
7010e4b17023SJohn Marino /*
7011e4b17023SJohn Marino Previously we kept track of the label's entire context in diagnose_sb_[12]
7012e4b17023SJohn Marino so we could traverse it and issue a correct "exit" or "enter" error
7013e4b17023SJohn Marino message upon a structured block violation.
7014e4b17023SJohn Marino
7015e4b17023SJohn Marino We built the context by building a list with tree_cons'ing, but there is
7016e4b17023SJohn Marino no easy counterpart in gimple tuples. It seems like far too much work
7017e4b17023SJohn Marino for issuing exit/enter error messages. If someone really misses the
7018e4b17023SJohn Marino distinct error message... patches welcome.
7019e4b17023SJohn Marino */
7020e4b17023SJohn Marino
7021e4b17023SJohn Marino #if 0
7022e4b17023SJohn Marino /* Try to avoid confusing the user by producing and error message
7023e4b17023SJohn Marino with correct "exit" or "enter" verbiage. We prefer "exit"
7024e4b17023SJohn Marino unless we can show that LABEL_CTX is nested within BRANCH_CTX. */
7025e4b17023SJohn Marino if (branch_ctx == NULL)
7026e4b17023SJohn Marino exit_p = false;
7027e4b17023SJohn Marino else
7028e4b17023SJohn Marino {
7029e4b17023SJohn Marino while (label_ctx)
7030e4b17023SJohn Marino {
7031e4b17023SJohn Marino if (TREE_VALUE (label_ctx) == branch_ctx)
7032e4b17023SJohn Marino {
7033e4b17023SJohn Marino exit_p = false;
7034e4b17023SJohn Marino break;
7035e4b17023SJohn Marino }
7036e4b17023SJohn Marino label_ctx = TREE_CHAIN (label_ctx);
7037e4b17023SJohn Marino }
7038e4b17023SJohn Marino }
7039e4b17023SJohn Marino
7040e4b17023SJohn Marino if (exit_p)
7041e4b17023SJohn Marino error ("invalid exit from OpenMP structured block");
7042e4b17023SJohn Marino else
7043e4b17023SJohn Marino error ("invalid entry to OpenMP structured block");
7044e4b17023SJohn Marino #endif
7045e4b17023SJohn Marino
7046e4b17023SJohn Marino /* If it's obvious we have an invalid entry, be specific about the error. */
7047e4b17023SJohn Marino if (branch_ctx == NULL)
7048e4b17023SJohn Marino error ("invalid entry to OpenMP structured block");
7049e4b17023SJohn Marino else
7050e4b17023SJohn Marino /* Otherwise, be vague and lazy, but efficient. */
7051e4b17023SJohn Marino error ("invalid branch to/from an OpenMP structured block");
7052e4b17023SJohn Marino
7053e4b17023SJohn Marino gsi_replace (gsi_p, gimple_build_nop (), false);
7054e4b17023SJohn Marino return true;
7055e4b17023SJohn Marino }
7056e4b17023SJohn Marino
7057e4b17023SJohn Marino /* Pass 1: Create a minimal tree of OpenMP structured blocks, and record
7058e4b17023SJohn Marino where each label is found. */
7059e4b17023SJohn Marino
7060e4b17023SJohn Marino static tree
diagnose_sb_1(gimple_stmt_iterator * gsi_p,bool * handled_ops_p,struct walk_stmt_info * wi)7061e4b17023SJohn Marino diagnose_sb_1 (gimple_stmt_iterator *gsi_p, bool *handled_ops_p,
7062e4b17023SJohn Marino struct walk_stmt_info *wi)
7063e4b17023SJohn Marino {
7064e4b17023SJohn Marino gimple context = (gimple) wi->info;
7065e4b17023SJohn Marino gimple inner_context;
7066e4b17023SJohn Marino gimple stmt = gsi_stmt (*gsi_p);
7067e4b17023SJohn Marino
7068e4b17023SJohn Marino *handled_ops_p = true;
7069e4b17023SJohn Marino
7070e4b17023SJohn Marino switch (gimple_code (stmt))
7071e4b17023SJohn Marino {
7072e4b17023SJohn Marino WALK_SUBSTMTS;
7073e4b17023SJohn Marino
7074e4b17023SJohn Marino case GIMPLE_OMP_PARALLEL:
7075e4b17023SJohn Marino case GIMPLE_OMP_TASK:
7076e4b17023SJohn Marino case GIMPLE_OMP_SECTIONS:
7077e4b17023SJohn Marino case GIMPLE_OMP_SINGLE:
7078e4b17023SJohn Marino case GIMPLE_OMP_SECTION:
7079e4b17023SJohn Marino case GIMPLE_OMP_MASTER:
7080e4b17023SJohn Marino case GIMPLE_OMP_ORDERED:
7081e4b17023SJohn Marino case GIMPLE_OMP_CRITICAL:
7082e4b17023SJohn Marino /* The minimal context here is just the current OMP construct. */
7083e4b17023SJohn Marino inner_context = stmt;
7084e4b17023SJohn Marino wi->info = inner_context;
7085e4b17023SJohn Marino walk_gimple_seq (gimple_omp_body (stmt), diagnose_sb_1, NULL, wi);
7086e4b17023SJohn Marino wi->info = context;
7087e4b17023SJohn Marino break;
7088e4b17023SJohn Marino
7089e4b17023SJohn Marino case GIMPLE_OMP_FOR:
7090e4b17023SJohn Marino inner_context = stmt;
7091e4b17023SJohn Marino wi->info = inner_context;
7092e4b17023SJohn Marino /* gimple_omp_for_{index,initial,final} are all DECLs; no need to
7093e4b17023SJohn Marino walk them. */
7094e4b17023SJohn Marino walk_gimple_seq (gimple_omp_for_pre_body (stmt),
7095e4b17023SJohn Marino diagnose_sb_1, NULL, wi);
7096e4b17023SJohn Marino walk_gimple_seq (gimple_omp_body (stmt), diagnose_sb_1, NULL, wi);
7097e4b17023SJohn Marino wi->info = context;
7098e4b17023SJohn Marino break;
7099e4b17023SJohn Marino
7100e4b17023SJohn Marino case GIMPLE_LABEL:
7101e4b17023SJohn Marino splay_tree_insert (all_labels, (splay_tree_key) gimple_label_label (stmt),
7102e4b17023SJohn Marino (splay_tree_value) context);
7103e4b17023SJohn Marino break;
7104e4b17023SJohn Marino
7105e4b17023SJohn Marino default:
7106e4b17023SJohn Marino break;
7107e4b17023SJohn Marino }
7108e4b17023SJohn Marino
7109e4b17023SJohn Marino return NULL_TREE;
7110e4b17023SJohn Marino }
7111e4b17023SJohn Marino
7112e4b17023SJohn Marino /* Pass 2: Check each branch and see if its context differs from that of
7113e4b17023SJohn Marino the destination label's context. */
7114e4b17023SJohn Marino
7115e4b17023SJohn Marino static tree
diagnose_sb_2(gimple_stmt_iterator * gsi_p,bool * handled_ops_p,struct walk_stmt_info * wi)7116e4b17023SJohn Marino diagnose_sb_2 (gimple_stmt_iterator *gsi_p, bool *handled_ops_p,
7117e4b17023SJohn Marino struct walk_stmt_info *wi)
7118e4b17023SJohn Marino {
7119e4b17023SJohn Marino gimple context = (gimple) wi->info;
7120e4b17023SJohn Marino splay_tree_node n;
7121e4b17023SJohn Marino gimple stmt = gsi_stmt (*gsi_p);
7122e4b17023SJohn Marino
7123e4b17023SJohn Marino *handled_ops_p = true;
7124e4b17023SJohn Marino
7125e4b17023SJohn Marino switch (gimple_code (stmt))
7126e4b17023SJohn Marino {
7127e4b17023SJohn Marino WALK_SUBSTMTS;
7128e4b17023SJohn Marino
7129e4b17023SJohn Marino case GIMPLE_OMP_PARALLEL:
7130e4b17023SJohn Marino case GIMPLE_OMP_TASK:
7131e4b17023SJohn Marino case GIMPLE_OMP_SECTIONS:
7132e4b17023SJohn Marino case GIMPLE_OMP_SINGLE:
7133e4b17023SJohn Marino case GIMPLE_OMP_SECTION:
7134e4b17023SJohn Marino case GIMPLE_OMP_MASTER:
7135e4b17023SJohn Marino case GIMPLE_OMP_ORDERED:
7136e4b17023SJohn Marino case GIMPLE_OMP_CRITICAL:
7137e4b17023SJohn Marino wi->info = stmt;
7138e4b17023SJohn Marino walk_gimple_seq (gimple_omp_body (stmt), diagnose_sb_2, NULL, wi);
7139e4b17023SJohn Marino wi->info = context;
7140e4b17023SJohn Marino break;
7141e4b17023SJohn Marino
7142e4b17023SJohn Marino case GIMPLE_OMP_FOR:
7143e4b17023SJohn Marino wi->info = stmt;
7144e4b17023SJohn Marino /* gimple_omp_for_{index,initial,final} are all DECLs; no need to
7145e4b17023SJohn Marino walk them. */
7146e4b17023SJohn Marino walk_gimple_seq (gimple_omp_for_pre_body (stmt),
7147e4b17023SJohn Marino diagnose_sb_2, NULL, wi);
7148e4b17023SJohn Marino walk_gimple_seq (gimple_omp_body (stmt), diagnose_sb_2, NULL, wi);
7149e4b17023SJohn Marino wi->info = context;
7150e4b17023SJohn Marino break;
7151e4b17023SJohn Marino
7152e4b17023SJohn Marino case GIMPLE_COND:
7153e4b17023SJohn Marino {
7154e4b17023SJohn Marino tree lab = gimple_cond_true_label (stmt);
7155e4b17023SJohn Marino if (lab)
7156e4b17023SJohn Marino {
7157e4b17023SJohn Marino n = splay_tree_lookup (all_labels,
7158e4b17023SJohn Marino (splay_tree_key) lab);
7159e4b17023SJohn Marino diagnose_sb_0 (gsi_p, context,
7160e4b17023SJohn Marino n ? (gimple) n->value : NULL);
7161e4b17023SJohn Marino }
7162e4b17023SJohn Marino lab = gimple_cond_false_label (stmt);
7163e4b17023SJohn Marino if (lab)
7164e4b17023SJohn Marino {
7165e4b17023SJohn Marino n = splay_tree_lookup (all_labels,
7166e4b17023SJohn Marino (splay_tree_key) lab);
7167e4b17023SJohn Marino diagnose_sb_0 (gsi_p, context,
7168e4b17023SJohn Marino n ? (gimple) n->value : NULL);
7169e4b17023SJohn Marino }
7170e4b17023SJohn Marino }
7171e4b17023SJohn Marino break;
7172e4b17023SJohn Marino
7173e4b17023SJohn Marino case GIMPLE_GOTO:
7174e4b17023SJohn Marino {
7175e4b17023SJohn Marino tree lab = gimple_goto_dest (stmt);
7176e4b17023SJohn Marino if (TREE_CODE (lab) != LABEL_DECL)
7177e4b17023SJohn Marino break;
7178e4b17023SJohn Marino
7179e4b17023SJohn Marino n = splay_tree_lookup (all_labels, (splay_tree_key) lab);
7180e4b17023SJohn Marino diagnose_sb_0 (gsi_p, context, n ? (gimple) n->value : NULL);
7181e4b17023SJohn Marino }
7182e4b17023SJohn Marino break;
7183e4b17023SJohn Marino
7184e4b17023SJohn Marino case GIMPLE_SWITCH:
7185e4b17023SJohn Marino {
7186e4b17023SJohn Marino unsigned int i;
7187e4b17023SJohn Marino for (i = 0; i < gimple_switch_num_labels (stmt); ++i)
7188e4b17023SJohn Marino {
7189e4b17023SJohn Marino tree lab = CASE_LABEL (gimple_switch_label (stmt, i));
7190e4b17023SJohn Marino n = splay_tree_lookup (all_labels, (splay_tree_key) lab);
7191e4b17023SJohn Marino if (n && diagnose_sb_0 (gsi_p, context, (gimple) n->value))
7192e4b17023SJohn Marino break;
7193e4b17023SJohn Marino }
7194e4b17023SJohn Marino }
7195e4b17023SJohn Marino break;
7196e4b17023SJohn Marino
7197e4b17023SJohn Marino case GIMPLE_RETURN:
7198e4b17023SJohn Marino diagnose_sb_0 (gsi_p, context, NULL);
7199e4b17023SJohn Marino break;
7200e4b17023SJohn Marino
7201e4b17023SJohn Marino default:
7202e4b17023SJohn Marino break;
7203e4b17023SJohn Marino }
7204e4b17023SJohn Marino
7205e4b17023SJohn Marino return NULL_TREE;
7206e4b17023SJohn Marino }
7207e4b17023SJohn Marino
7208e4b17023SJohn Marino static unsigned int
diagnose_omp_structured_block_errors(void)7209e4b17023SJohn Marino diagnose_omp_structured_block_errors (void)
7210e4b17023SJohn Marino {
7211e4b17023SJohn Marino struct walk_stmt_info wi;
7212e4b17023SJohn Marino gimple_seq body = gimple_body (current_function_decl);
7213e4b17023SJohn Marino
7214e4b17023SJohn Marino all_labels = splay_tree_new (splay_tree_compare_pointers, 0, 0);
7215e4b17023SJohn Marino
7216e4b17023SJohn Marino memset (&wi, 0, sizeof (wi));
7217e4b17023SJohn Marino walk_gimple_seq (body, diagnose_sb_1, NULL, &wi);
7218e4b17023SJohn Marino
7219e4b17023SJohn Marino memset (&wi, 0, sizeof (wi));
7220e4b17023SJohn Marino wi.want_locations = true;
7221e4b17023SJohn Marino walk_gimple_seq (body, diagnose_sb_2, NULL, &wi);
7222e4b17023SJohn Marino
7223e4b17023SJohn Marino splay_tree_delete (all_labels);
7224e4b17023SJohn Marino all_labels = NULL;
7225e4b17023SJohn Marino
7226e4b17023SJohn Marino return 0;
7227e4b17023SJohn Marino }
7228e4b17023SJohn Marino
7229e4b17023SJohn Marino static bool
gate_diagnose_omp_blocks(void)7230e4b17023SJohn Marino gate_diagnose_omp_blocks (void)
7231e4b17023SJohn Marino {
7232e4b17023SJohn Marino return flag_openmp != 0;
7233e4b17023SJohn Marino }
7234e4b17023SJohn Marino
7235e4b17023SJohn Marino struct gimple_opt_pass pass_diagnose_omp_blocks =
7236e4b17023SJohn Marino {
7237e4b17023SJohn Marino {
7238e4b17023SJohn Marino GIMPLE_PASS,
7239e4b17023SJohn Marino "*diagnose_omp_blocks", /* name */
7240e4b17023SJohn Marino gate_diagnose_omp_blocks, /* gate */
7241e4b17023SJohn Marino diagnose_omp_structured_block_errors, /* execute */
7242e4b17023SJohn Marino NULL, /* sub */
7243e4b17023SJohn Marino NULL, /* next */
7244e4b17023SJohn Marino 0, /* static_pass_number */
7245e4b17023SJohn Marino TV_NONE, /* tv_id */
7246e4b17023SJohn Marino PROP_gimple_any, /* properties_required */
7247e4b17023SJohn Marino 0, /* properties_provided */
7248e4b17023SJohn Marino 0, /* properties_destroyed */
7249e4b17023SJohn Marino 0, /* todo_flags_start */
7250e4b17023SJohn Marino 0, /* todo_flags_finish */
7251e4b17023SJohn Marino }
7252e4b17023SJohn Marino };
7253e4b17023SJohn Marino
7254e4b17023SJohn Marino #include "gt-omp-low.h"
7255