xref: /openbsd/gnu/gcc/gcc/c-omp.c (revision 404b540a)
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 
8 This file is part of GCC.
9 
10 GCC is free software; you can redistribute it and/or modify it under
11 the terms of the GNU General Public License as published by the Free
12 Software Foundation; either version 2, or (at your option) any later
13 version.
14 
15 GCC is distributed in the hope that it will be useful, but WITHOUT ANY
16 WARRANTY; without even the implied warranty of MERCHANTABILITY or
17 FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
18 for more details.
19 
20 You should have received a copy of the GNU General Public License
21 along with GCC; see the file COPYING.  If not, write to the Free
22 Software Foundation, 51 Franklin Street, Fifth Floor, Boston, MA
23 02110-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 
41 tree
c_finish_omp_master(tree stmt)42 c_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 
51 tree
c_finish_omp_critical(tree body,tree name)52 c_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 
64 tree
c_finish_omp_ordered(tree stmt)65 c_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 
73 void
c_finish_omp_barrier(void)74 c_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 
90 tree
c_finish_omp_atomic(enum tree_code code,tree lhs,tree rhs)91 c_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 
147 void
c_finish_omp_flush(void)148 c_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 
161 static tree
check_omp_for_incr_expr(tree exp,tree decl)162 check_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 
206 tree
c_finish_omp_for(location_t locus,tree decl,tree init,tree cond,tree incr,tree body,tree pre_body)207 c_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 
391 void
c_split_parallel_clauses(tree clauses,tree * par_clauses,tree * ws_clauses)392 c_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 
432 enum omp_clause_default_kind
c_omp_predetermined_sharing(tree decl)433 c_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