xref: /dflybsd-src/contrib/gcc-4.7/gcc/omp-low.c (revision 81fc95a5293ee307c688a350a3feb4734aaddbb4)
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, &copyin_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 (&copyout);
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 			      &copyin_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