1/* This file contains routines to construct GNU OpenMP constructs,
2   called from parsing in the C and C++ front ends.
3
4   Copyright (C) 2005 Free Software Foundation, Inc.
5   Contributed by Richard Henderson <rth@redhat.com>,
6		  Diego Novillo <dnovillo@redhat.com>.
7
8This file is part of GCC.
9
10GCC is free software; you can redistribute it and/or modify it under
11the terms of the GNU General Public License as published by the Free
12Software Foundation; either version 2, or (at your option) any later
13version.
14
15GCC is distributed in the hope that it will be useful, but WITHOUT ANY
16WARRANTY; without even the implied warranty of MERCHANTABILITY or
17FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
18for more details.
19
20You should have received a copy of the GNU General Public License
21along with GCC; see the file COPYING.  If not, write to the Free
22Software Foundation, 51 Franklin Street, Fifth Floor, Boston, MA
2302110-1301, USA.  */
24
25#include "config.h"
26#include "system.h"
27#include "coretypes.h"
28#include "tm.h"
29#include "tree.h"
30#include "function.h"
31#include "c-common.h"
32#include "toplev.h"
33#include "tree-gimple.h"
34#include "bitmap.h"
35#include "langhooks.h"
36
37
38/* Complete a #pragma omp master construct.  STMT is the structured-block
39   that follows the pragma.  */
40
41tree
42c_finish_omp_master (tree stmt)
43{
44  return add_stmt (build1 (OMP_MASTER, void_type_node, stmt));
45}
46
47/* Complete a #pragma omp critical construct.  STMT is the structured-block
48   that follows the pragma, NAME is the identifier in the pragma, or null
49   if it was omitted.  */
50
51tree
52c_finish_omp_critical (tree body, tree name)
53{
54  tree stmt = make_node (OMP_CRITICAL);
55  TREE_TYPE (stmt) = void_type_node;
56  OMP_CRITICAL_BODY (stmt) = body;
57  OMP_CRITICAL_NAME (stmt) = name;
58  return add_stmt (stmt);
59}
60
61/* Complete a #pragma omp ordered construct.  STMT is the structured-block
62   that follows the pragma.  */
63
64tree
65c_finish_omp_ordered (tree stmt)
66{
67  return add_stmt (build1 (OMP_ORDERED, void_type_node, stmt));
68}
69
70
71/* Complete a #pragma omp barrier construct.  */
72
73void
74c_finish_omp_barrier (void)
75{
76  tree x;
77
78  x = built_in_decls[BUILT_IN_GOMP_BARRIER];
79  x = build_function_call_expr (x, NULL);
80  add_stmt (x);
81}
82
83
84/* Complete a #pragma omp atomic construct.  The expression to be
85   implemented atomically is LHS code= RHS.  The value returned is
86   either error_mark_node (if the construct was erroneous) or an
87   OMP_ATOMIC node which should be added to the current statement tree
88   with add_stmt.  */
89
90tree
91c_finish_omp_atomic (enum tree_code code, tree lhs, tree rhs)
92{
93  tree x, type, addr;
94
95  if (lhs == error_mark_node || rhs == error_mark_node)
96    return error_mark_node;
97
98  /* ??? According to one reading of the OpenMP spec, complex type are
99     supported, but there are no atomic stores for any architecture.
100     But at least icc 9.0 doesn't support complex types here either.
101     And lets not even talk about vector types...  */
102  type = TREE_TYPE (lhs);
103  if (!INTEGRAL_TYPE_P (type)
104      && !POINTER_TYPE_P (type)
105      && !SCALAR_FLOAT_TYPE_P (type))
106    {
107      error ("invalid expression type for %<#pragma omp atomic%>");
108      return error_mark_node;
109    }
110
111  /* ??? Validate that rhs does not overlap lhs.  */
112
113  /* Take and save the address of the lhs.  From then on we'll reference it
114     via indirection.  */
115  addr = build_unary_op (ADDR_EXPR, lhs, 0);
116  if (addr == error_mark_node)
117    return error_mark_node;
118  addr = save_expr (addr);
119  if (TREE_CODE (addr) != SAVE_EXPR
120      && (TREE_CODE (addr) != ADDR_EXPR
121	  || TREE_CODE (TREE_OPERAND (addr, 0)) != VAR_DECL))
122    {
123      /* Make sure LHS is simple enough so that goa_lhs_expr_p can recognize
124	 it even after unsharing function body.  */
125      tree var = create_tmp_var_raw (TREE_TYPE (addr), NULL);
126      addr = build4 (TARGET_EXPR, TREE_TYPE (addr), var, addr, NULL, NULL);
127    }
128  lhs = build_indirect_ref (addr, NULL);
129
130  /* There are lots of warnings, errors, and conversions that need to happen
131     in the course of interpreting a statement.  Use the normal mechanisms
132     to do this, and then take it apart again.  */
133  x = build_modify_expr (lhs, code, rhs);
134  if (x == error_mark_node)
135    return error_mark_node;
136  gcc_assert (TREE_CODE (x) == MODIFY_EXPR);
137  rhs = TREE_OPERAND (x, 1);
138
139  /* Punt the actual generation of atomic operations to common code.  */
140  return build2 (OMP_ATOMIC, void_type_node, addr, rhs);
141}
142
143
144/* Complete a #pragma omp flush construct.  We don't do anything with the
145   variable list that the syntax allows.  */
146
147void
148c_finish_omp_flush (void)
149{
150  tree x;
151
152  x = built_in_decls[BUILT_IN_SYNCHRONIZE];
153  x = build_function_call_expr (x, NULL);
154  add_stmt (x);
155}
156
157
158/* Check and canonicalize #pragma omp for increment expression.
159   Helper function for c_finish_omp_for.  */
160
161static tree
162check_omp_for_incr_expr (tree exp, tree decl)
163{
164  tree t;
165
166  if (!INTEGRAL_TYPE_P (TREE_TYPE (exp))
167      || TYPE_PRECISION (TREE_TYPE (exp)) < TYPE_PRECISION (TREE_TYPE (decl)))
168    return error_mark_node;
169
170  if (exp == decl)
171    return build_int_cst (TREE_TYPE (exp), 0);
172
173  switch (TREE_CODE (exp))
174    {
175    case NOP_EXPR:
176      t = check_omp_for_incr_expr (TREE_OPERAND (exp, 0), decl);
177      if (t != error_mark_node)
178        return fold_convert (TREE_TYPE (exp), t);
179      break;
180    case MINUS_EXPR:
181      t = check_omp_for_incr_expr (TREE_OPERAND (exp, 0), decl);
182      if (t != error_mark_node)
183        return fold_build2 (MINUS_EXPR, TREE_TYPE (exp), t, TREE_OPERAND (exp, 1));
184      break;
185    case PLUS_EXPR:
186      t = check_omp_for_incr_expr (TREE_OPERAND (exp, 0), decl);
187      if (t != error_mark_node)
188        return fold_build2 (PLUS_EXPR, TREE_TYPE (exp), t, TREE_OPERAND (exp, 1));
189      t = check_omp_for_incr_expr (TREE_OPERAND (exp, 1), decl);
190      if (t != error_mark_node)
191        return fold_build2 (PLUS_EXPR, TREE_TYPE (exp), TREE_OPERAND (exp, 0), t);
192      break;
193    default:
194      break;
195    }
196
197  return error_mark_node;
198}
199
200/* Validate and emit code for the OpenMP directive #pragma omp for.
201   INIT, COND, INCR, BODY and PRE_BODY are the five basic elements
202   of the loop (initialization expression, controlling predicate, increment
203   expression, body of the loop and statements to go before the loop).
204   DECL is the iteration variable.  */
205
206tree
207c_finish_omp_for (location_t locus, tree decl, tree init, tree cond,
208		  tree incr, tree body, tree pre_body)
209{
210  location_t elocus = locus;
211  bool fail = false;
212
213  if (EXPR_HAS_LOCATION (init))
214    elocus = EXPR_LOCATION (init);
215
216  /* Validate the iteration variable.  */
217  if (!INTEGRAL_TYPE_P (TREE_TYPE (decl)))
218    {
219      error ("%Hinvalid type for iteration variable %qE", &elocus, decl);
220      fail = true;
221    }
222  if (TYPE_UNSIGNED (TREE_TYPE (decl)))
223    warning (0, "%Hiteration variable %qE is unsigned", &elocus, decl);
224
225  /* In the case of "for (int i = 0...)", init will be a decl.  It should
226     have a DECL_INITIAL that we can turn into an assignment.  */
227  if (init == decl)
228    {
229      elocus = DECL_SOURCE_LOCATION (decl);
230
231      init = DECL_INITIAL (decl);
232      if (init == NULL)
233	{
234	  error ("%H%qE is not initialized", &elocus, decl);
235	  init = integer_zero_node;
236	  fail = true;
237	}
238
239      init = build_modify_expr (decl, NOP_EXPR, init);
240      SET_EXPR_LOCATION (init, elocus);
241    }
242  gcc_assert (TREE_CODE (init) == MODIFY_EXPR);
243  gcc_assert (TREE_OPERAND (init, 0) == decl);
244
245  if (cond == NULL_TREE)
246    {
247      error ("%Hmissing controlling predicate", &elocus);
248      fail = true;
249    }
250  else
251    {
252      bool cond_ok = false;
253
254      if (EXPR_HAS_LOCATION (cond))
255	elocus = EXPR_LOCATION (cond);
256
257      if (TREE_CODE (cond) == LT_EXPR
258	  || TREE_CODE (cond) == LE_EXPR
259	  || TREE_CODE (cond) == GT_EXPR
260	  || TREE_CODE (cond) == GE_EXPR)
261	{
262	  tree op0 = TREE_OPERAND (cond, 0);
263	  tree op1 = TREE_OPERAND (cond, 1);
264
265	  /* 2.5.1.  The comparison in the condition is computed in the type
266	     of DECL, otherwise the behavior is undefined.
267
268	     For example:
269	     long n; int i;
270	     i < n;
271
272	     according to ISO will be evaluated as:
273	     (long)i < n;
274
275	     We want to force:
276	     i < (int)n;  */
277	  if (TREE_CODE (op0) == NOP_EXPR
278	      && decl == TREE_OPERAND (op0, 0))
279	    {
280	      TREE_OPERAND (cond, 0) = TREE_OPERAND (op0, 0);
281	      TREE_OPERAND (cond, 1) = fold_build1 (NOP_EXPR, TREE_TYPE (decl),
282						    TREE_OPERAND (cond, 1));
283	    }
284	  else if (TREE_CODE (op1) == NOP_EXPR
285		   && decl == TREE_OPERAND (op1, 0))
286	    {
287	      TREE_OPERAND (cond, 1) = TREE_OPERAND (op1, 0);
288	      TREE_OPERAND (cond, 0) = fold_build1 (NOP_EXPR, TREE_TYPE (decl),
289						    TREE_OPERAND (cond, 0));
290	    }
291
292	  if (decl == TREE_OPERAND (cond, 0))
293	    cond_ok = true;
294	  else if (decl == TREE_OPERAND (cond, 1))
295	    {
296	      TREE_SET_CODE (cond, swap_tree_comparison (TREE_CODE (cond)));
297	      TREE_OPERAND (cond, 1) = TREE_OPERAND (cond, 0);
298	      TREE_OPERAND (cond, 0) = decl;
299	      cond_ok = true;
300	    }
301	}
302
303      if (!cond_ok)
304	{
305	  error ("%Hinvalid controlling predicate", &elocus);
306	  fail = true;
307	}
308    }
309
310  if (incr == NULL_TREE)
311    {
312      error ("%Hmissing increment expression", &elocus);
313      fail = true;
314    }
315  else
316    {
317      bool incr_ok = false;
318
319      if (EXPR_HAS_LOCATION (incr))
320	elocus = EXPR_LOCATION (incr);
321
322      /* Check all the valid increment expressions: v++, v--, ++v, --v,
323	 v = v + incr, v = incr + v and v = v - incr.  */
324      switch (TREE_CODE (incr))
325	{
326	case POSTINCREMENT_EXPR:
327	case PREINCREMENT_EXPR:
328	case POSTDECREMENT_EXPR:
329	case PREDECREMENT_EXPR:
330	  incr_ok = (TREE_OPERAND (incr, 0) == decl);
331	  break;
332
333	case MODIFY_EXPR:
334	  if (TREE_OPERAND (incr, 0) != decl)
335	    break;
336	  if (TREE_OPERAND (incr, 1) == decl)
337	    break;
338	  if (TREE_CODE (TREE_OPERAND (incr, 1)) == PLUS_EXPR
339	      && (TREE_OPERAND (TREE_OPERAND (incr, 1), 0) == decl
340		  || TREE_OPERAND (TREE_OPERAND (incr, 1), 1) == decl))
341	    incr_ok = true;
342	  else if (TREE_CODE (TREE_OPERAND (incr, 1)) == MINUS_EXPR
343		   && TREE_OPERAND (TREE_OPERAND (incr, 1), 0) == decl)
344	    incr_ok = true;
345	  else
346	    {
347	      tree t = check_omp_for_incr_expr (TREE_OPERAND (incr, 1), decl);
348	      if (t != error_mark_node)
349		{
350		  incr_ok = true;
351		  t = build2 (PLUS_EXPR, TREE_TYPE (decl), decl, t);
352		  incr = build2 (MODIFY_EXPR, void_type_node, decl, t);
353		}
354	    }
355	  break;
356
357	default:
358	  break;
359	}
360      if (!incr_ok)
361	{
362	  error ("%Hinvalid increment expression", &elocus);
363	  fail = true;
364	}
365    }
366
367  if (fail)
368    return NULL;
369  else
370    {
371      tree t = make_node (OMP_FOR);
372
373      TREE_TYPE (t) = void_type_node;
374      OMP_FOR_INIT (t) = init;
375      OMP_FOR_COND (t) = cond;
376      OMP_FOR_INCR (t) = incr;
377      OMP_FOR_BODY (t) = body;
378      OMP_FOR_PRE_BODY (t) = pre_body;
379
380      SET_EXPR_LOCATION (t, locus);
381      return add_stmt (t);
382    }
383}
384
385
386/* Divide CLAUSES into two lists: those that apply to a parallel construct,
387   and those that apply to a work-sharing construct.  Place the results in
388   *PAR_CLAUSES and *WS_CLAUSES respectively.  In addition, add a nowait
389   clause to the work-sharing list.  */
390
391void
392c_split_parallel_clauses (tree clauses, tree *par_clauses, tree *ws_clauses)
393{
394  tree next;
395
396  *par_clauses = NULL;
397  *ws_clauses = build_omp_clause (OMP_CLAUSE_NOWAIT);
398
399  for (; clauses ; clauses = next)
400    {
401      next = OMP_CLAUSE_CHAIN (clauses);
402
403      switch (OMP_CLAUSE_CODE (clauses))
404	{
405	case OMP_CLAUSE_PRIVATE:
406	case OMP_CLAUSE_SHARED:
407	case OMP_CLAUSE_FIRSTPRIVATE:
408	case OMP_CLAUSE_LASTPRIVATE:
409	case OMP_CLAUSE_REDUCTION:
410	case OMP_CLAUSE_COPYIN:
411	case OMP_CLAUSE_IF:
412	case OMP_CLAUSE_NUM_THREADS:
413	case OMP_CLAUSE_DEFAULT:
414	  OMP_CLAUSE_CHAIN (clauses) = *par_clauses;
415	  *par_clauses = clauses;
416	  break;
417
418	case OMP_CLAUSE_SCHEDULE:
419	case OMP_CLAUSE_ORDERED:
420	  OMP_CLAUSE_CHAIN (clauses) = *ws_clauses;
421	  *ws_clauses = clauses;
422	  break;
423
424	default:
425	  gcc_unreachable ();
426	}
427    }
428}
429
430/* True if OpenMP sharing attribute of DECL is predetermined.  */
431
432enum omp_clause_default_kind
433c_omp_predetermined_sharing (tree decl)
434{
435  /* Variables with const-qualified type having no mutable member
436     are predetermined shared.  */
437  if (TREE_READONLY (decl))
438    return OMP_CLAUSE_DEFAULT_SHARED;
439
440  return OMP_CLAUSE_DEFAULT_UNSPECIFIED;
441}
442