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, 2007, 2008, 2009, 2010, 2011
5 Free Software Foundation, Inc.
6 Contributed by Richard Henderson <rth@redhat.com>,
7 Diego Novillo <dnovillo@redhat.com>.
8
9 This file is part of GCC.
10
11 GCC is free software; you can redistribute it and/or modify it under
12 the terms of the GNU General Public License as published by the Free
13 Software Foundation; either version 3, or (at your option) any later
14 version.
15
16 GCC is distributed in the hope that it will be useful, but WITHOUT ANY
17 WARRANTY; without even the implied warranty of MERCHANTABILITY or
18 FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
19 for more details.
20
21 You should have received a copy of the GNU General Public License
22 along with GCC; see the file COPYING3. If not see
23 <http://www.gnu.org/licenses/>. */
24
25 #include "config.h"
26 #include "system.h"
27 #include "coretypes.h"
28 #include "tree.h"
29 #include "c-common.h"
30 #include "gimple.h" /* For create_tmp_var_raw. */
31 #include "langhooks.h"
32
33
34 /* Complete a #pragma omp master construct. STMT is the structured-block
35 that follows the pragma. LOC is the l*/
36
37 tree
c_finish_omp_master(location_t loc,tree stmt)38 c_finish_omp_master (location_t loc, tree stmt)
39 {
40 tree t = add_stmt (build1 (OMP_MASTER, void_type_node, stmt));
41 SET_EXPR_LOCATION (t, loc);
42 return t;
43 }
44
45 /* Complete a #pragma omp critical construct. STMT is the structured-block
46 that follows the pragma, NAME is the identifier in the pragma, or null
47 if it was omitted. LOC is the location of the #pragma. */
48
49 tree
c_finish_omp_critical(location_t loc,tree body,tree name)50 c_finish_omp_critical (location_t loc, tree body, tree name)
51 {
52 tree stmt = make_node (OMP_CRITICAL);
53 TREE_TYPE (stmt) = void_type_node;
54 OMP_CRITICAL_BODY (stmt) = body;
55 OMP_CRITICAL_NAME (stmt) = name;
56 SET_EXPR_LOCATION (stmt, loc);
57 return add_stmt (stmt);
58 }
59
60 /* Complete a #pragma omp ordered construct. STMT is the structured-block
61 that follows the pragma. LOC is the location of the #pragma. */
62
63 tree
c_finish_omp_ordered(location_t loc,tree stmt)64 c_finish_omp_ordered (location_t loc, tree stmt)
65 {
66 tree t = build1 (OMP_ORDERED, void_type_node, stmt);
67 SET_EXPR_LOCATION (t, loc);
68 return add_stmt (t);
69 }
70
71
72 /* Complete a #pragma omp barrier construct. LOC is the location of
73 the #pragma. */
74
75 void
c_finish_omp_barrier(location_t loc)76 c_finish_omp_barrier (location_t loc)
77 {
78 tree x;
79
80 x = builtin_decl_explicit (BUILT_IN_GOMP_BARRIER);
81 x = build_call_expr_loc (loc, x, 0);
82 add_stmt (x);
83 }
84
85
86 /* Complete a #pragma omp taskwait construct. LOC is the location of the
87 pragma. */
88
89 void
c_finish_omp_taskwait(location_t loc)90 c_finish_omp_taskwait (location_t loc)
91 {
92 tree x;
93
94 x = builtin_decl_explicit (BUILT_IN_GOMP_TASKWAIT);
95 x = build_call_expr_loc (loc, x, 0);
96 add_stmt (x);
97 }
98
99
100 /* Complete a #pragma omp taskyield construct. LOC is the location of the
101 pragma. */
102
103 void
c_finish_omp_taskyield(location_t loc)104 c_finish_omp_taskyield (location_t loc)
105 {
106 tree x;
107
108 x = builtin_decl_explicit (BUILT_IN_GOMP_TASKYIELD);
109 x = build_call_expr_loc (loc, x, 0);
110 add_stmt (x);
111 }
112
113
114 /* Complete a #pragma omp atomic construct. For CODE OMP_ATOMIC
115 the expression to be implemented atomically is LHS opcode= RHS.
116 For OMP_ATOMIC_READ V = LHS, for OMP_ATOMIC_CAPTURE_{NEW,OLD} LHS
117 opcode= RHS with the new or old content of LHS returned.
118 LOC is the location of the atomic statement. The value returned
119 is either error_mark_node (if the construct was erroneous) or an
120 OMP_ATOMIC* node which should be added to the current statement
121 tree with add_stmt. */
122
123 tree
c_finish_omp_atomic(location_t loc,enum tree_code code,enum tree_code opcode,tree lhs,tree rhs,tree v,tree lhs1,tree rhs1)124 c_finish_omp_atomic (location_t loc, enum tree_code code,
125 enum tree_code opcode, tree lhs, tree rhs,
126 tree v, tree lhs1, tree rhs1)
127 {
128 tree x, type, addr;
129
130 if (lhs == error_mark_node || rhs == error_mark_node
131 || v == error_mark_node || lhs1 == error_mark_node
132 || rhs1 == error_mark_node)
133 return error_mark_node;
134
135 /* ??? According to one reading of the OpenMP spec, complex type are
136 supported, but there are no atomic stores for any architecture.
137 But at least icc 9.0 doesn't support complex types here either.
138 And lets not even talk about vector types... */
139 type = TREE_TYPE (lhs);
140 if (!INTEGRAL_TYPE_P (type)
141 && !POINTER_TYPE_P (type)
142 && !SCALAR_FLOAT_TYPE_P (type))
143 {
144 error_at (loc, "invalid expression type for %<#pragma omp atomic%>");
145 return error_mark_node;
146 }
147
148 /* ??? Validate that rhs does not overlap lhs. */
149
150 /* Take and save the address of the lhs. From then on we'll reference it
151 via indirection. */
152 addr = build_unary_op (loc, ADDR_EXPR, lhs, 0);
153 if (addr == error_mark_node)
154 return error_mark_node;
155 addr = save_expr (addr);
156 if (TREE_CODE (addr) != SAVE_EXPR
157 && (TREE_CODE (addr) != ADDR_EXPR
158 || TREE_CODE (TREE_OPERAND (addr, 0)) != VAR_DECL))
159 {
160 /* Make sure LHS is simple enough so that goa_lhs_expr_p can recognize
161 it even after unsharing function body. */
162 tree var = create_tmp_var_raw (TREE_TYPE (addr), NULL);
163 DECL_CONTEXT (var) = current_function_decl;
164 addr = build4 (TARGET_EXPR, TREE_TYPE (addr), var, addr, NULL, NULL);
165 }
166 lhs = build_indirect_ref (loc, addr, RO_NULL);
167
168 if (code == OMP_ATOMIC_READ)
169 {
170 x = build1 (OMP_ATOMIC_READ, type, addr);
171 SET_EXPR_LOCATION (x, loc);
172 return build_modify_expr (loc, v, NULL_TREE, NOP_EXPR,
173 loc, x, NULL_TREE);
174 return x;
175 }
176
177 /* There are lots of warnings, errors, and conversions that need to happen
178 in the course of interpreting a statement. Use the normal mechanisms
179 to do this, and then take it apart again. */
180 x = build_modify_expr (input_location, lhs, NULL_TREE, opcode,
181 input_location, rhs, NULL_TREE);
182 if (x == error_mark_node)
183 return error_mark_node;
184 gcc_assert (TREE_CODE (x) == MODIFY_EXPR);
185 rhs = TREE_OPERAND (x, 1);
186
187 /* Punt the actual generation of atomic operations to common code. */
188 if (code == OMP_ATOMIC)
189 type = void_type_node;
190 x = build2 (code, type, addr, rhs);
191 SET_EXPR_LOCATION (x, loc);
192
193 /* Generally it is hard to prove lhs1 and lhs are the same memory
194 location, just diagnose different variables. */
195 if (rhs1
196 && TREE_CODE (rhs1) == VAR_DECL
197 && TREE_CODE (lhs) == VAR_DECL
198 && rhs1 != lhs)
199 {
200 if (code == OMP_ATOMIC)
201 error_at (loc, "%<#pragma omp atomic update%> uses two different variables for memory");
202 else
203 error_at (loc, "%<#pragma omp atomic capture%> uses two different variables for memory");
204 return error_mark_node;
205 }
206
207 if (code != OMP_ATOMIC)
208 {
209 /* Generally it is hard to prove lhs1 and lhs are the same memory
210 location, just diagnose different variables. */
211 if (lhs1 && TREE_CODE (lhs1) == VAR_DECL && TREE_CODE (lhs) == VAR_DECL)
212 {
213 if (lhs1 != lhs)
214 {
215 error_at (loc, "%<#pragma omp atomic capture%> uses two different variables for memory");
216 return error_mark_node;
217 }
218 }
219 x = build_modify_expr (loc, v, NULL_TREE, NOP_EXPR,
220 loc, x, NULL_TREE);
221 if (rhs1 && rhs1 != lhs)
222 {
223 tree rhs1addr = build_unary_op (loc, ADDR_EXPR, rhs1, 0);
224 if (rhs1addr == error_mark_node)
225 return error_mark_node;
226 x = omit_one_operand_loc (loc, type, x, rhs1addr);
227 }
228 if (lhs1 && lhs1 != lhs)
229 {
230 tree lhs1addr = build_unary_op (loc, ADDR_EXPR, lhs1, 0);
231 if (lhs1addr == error_mark_node)
232 return error_mark_node;
233 if (code == OMP_ATOMIC_CAPTURE_OLD)
234 x = omit_one_operand_loc (loc, type, x, lhs1addr);
235 else
236 {
237 x = save_expr (x);
238 x = omit_two_operands_loc (loc, type, x, x, lhs1addr);
239 }
240 }
241 }
242 else if (rhs1 && rhs1 != lhs)
243 {
244 tree rhs1addr = build_unary_op (loc, ADDR_EXPR, rhs1, 0);
245 if (rhs1addr == error_mark_node)
246 return error_mark_node;
247 x = omit_one_operand_loc (loc, type, x, rhs1addr);
248 }
249
250 return x;
251 }
252
253
254 /* Complete a #pragma omp flush construct. We don't do anything with
255 the variable list that the syntax allows. LOC is the location of
256 the #pragma. */
257
258 void
c_finish_omp_flush(location_t loc)259 c_finish_omp_flush (location_t loc)
260 {
261 tree x;
262
263 x = builtin_decl_explicit (BUILT_IN_SYNC_SYNCHRONIZE);
264 x = build_call_expr_loc (loc, x, 0);
265 add_stmt (x);
266 }
267
268
269 /* Check and canonicalize #pragma omp for increment expression.
270 Helper function for c_finish_omp_for. */
271
272 static tree
check_omp_for_incr_expr(location_t loc,tree exp,tree decl)273 check_omp_for_incr_expr (location_t loc, tree exp, tree decl)
274 {
275 tree t;
276
277 if (!INTEGRAL_TYPE_P (TREE_TYPE (exp))
278 || TYPE_PRECISION (TREE_TYPE (exp)) < TYPE_PRECISION (TREE_TYPE (decl)))
279 return error_mark_node;
280
281 if (exp == decl)
282 return build_int_cst (TREE_TYPE (exp), 0);
283
284 switch (TREE_CODE (exp))
285 {
286 CASE_CONVERT:
287 t = check_omp_for_incr_expr (loc, TREE_OPERAND (exp, 0), decl);
288 if (t != error_mark_node)
289 return fold_convert_loc (loc, TREE_TYPE (exp), t);
290 break;
291 case MINUS_EXPR:
292 t = check_omp_for_incr_expr (loc, TREE_OPERAND (exp, 0), decl);
293 if (t != error_mark_node)
294 return fold_build2_loc (loc, MINUS_EXPR,
295 TREE_TYPE (exp), t, TREE_OPERAND (exp, 1));
296 break;
297 case PLUS_EXPR:
298 t = check_omp_for_incr_expr (loc, TREE_OPERAND (exp, 0), decl);
299 if (t != error_mark_node)
300 return fold_build2_loc (loc, PLUS_EXPR,
301 TREE_TYPE (exp), t, TREE_OPERAND (exp, 1));
302 t = check_omp_for_incr_expr (loc, TREE_OPERAND (exp, 1), decl);
303 if (t != error_mark_node)
304 return fold_build2_loc (loc, PLUS_EXPR,
305 TREE_TYPE (exp), TREE_OPERAND (exp, 0), t);
306 break;
307 case COMPOUND_EXPR:
308 {
309 /* cp_build_modify_expr forces preevaluation of the RHS to make
310 sure that it is evaluated before the lvalue-rvalue conversion
311 is applied to the LHS. Reconstruct the original expression. */
312 tree op0 = TREE_OPERAND (exp, 0);
313 if (TREE_CODE (op0) == TARGET_EXPR
314 && !VOID_TYPE_P (TREE_TYPE (op0)))
315 {
316 tree op1 = TREE_OPERAND (exp, 1);
317 tree temp = TARGET_EXPR_SLOT (op0);
318 if (TREE_CODE_CLASS (TREE_CODE (op1)) == tcc_binary
319 && TREE_OPERAND (op1, 1) == temp)
320 {
321 op1 = copy_node (op1);
322 TREE_OPERAND (op1, 1) = TARGET_EXPR_INITIAL (op0);
323 return check_omp_for_incr_expr (loc, op1, decl);
324 }
325 }
326 break;
327 }
328 default:
329 break;
330 }
331
332 return error_mark_node;
333 }
334
335 /* Validate and emit code for the OpenMP directive #pragma omp for.
336 DECLV is a vector of iteration variables, for each collapsed loop.
337 INITV, CONDV and INCRV are vectors containing initialization
338 expressions, controlling predicates and increment expressions.
339 BODY is the body of the loop and PRE_BODY statements that go before
340 the loop. */
341
342 tree
c_finish_omp_for(location_t locus,tree declv,tree initv,tree condv,tree incrv,tree body,tree pre_body)343 c_finish_omp_for (location_t locus, tree declv, tree initv, tree condv,
344 tree incrv, tree body, tree pre_body)
345 {
346 location_t elocus;
347 bool fail = false;
348 int i;
349
350 gcc_assert (TREE_VEC_LENGTH (declv) == TREE_VEC_LENGTH (initv));
351 gcc_assert (TREE_VEC_LENGTH (declv) == TREE_VEC_LENGTH (condv));
352 gcc_assert (TREE_VEC_LENGTH (declv) == TREE_VEC_LENGTH (incrv));
353 for (i = 0; i < TREE_VEC_LENGTH (declv); i++)
354 {
355 tree decl = TREE_VEC_ELT (declv, i);
356 tree init = TREE_VEC_ELT (initv, i);
357 tree cond = TREE_VEC_ELT (condv, i);
358 tree incr = TREE_VEC_ELT (incrv, i);
359
360 elocus = locus;
361 if (EXPR_HAS_LOCATION (init))
362 elocus = EXPR_LOCATION (init);
363
364 /* Validate the iteration variable. */
365 if (!INTEGRAL_TYPE_P (TREE_TYPE (decl))
366 && TREE_CODE (TREE_TYPE (decl)) != POINTER_TYPE)
367 {
368 error_at (elocus, "invalid type for iteration variable %qE", decl);
369 fail = true;
370 }
371
372 /* In the case of "for (int i = 0...)", init will be a decl. It should
373 have a DECL_INITIAL that we can turn into an assignment. */
374 if (init == decl)
375 {
376 elocus = DECL_SOURCE_LOCATION (decl);
377
378 init = DECL_INITIAL (decl);
379 if (init == NULL)
380 {
381 error_at (elocus, "%qE is not initialized", decl);
382 init = integer_zero_node;
383 fail = true;
384 }
385
386 init = build_modify_expr (elocus, decl, NULL_TREE, NOP_EXPR,
387 /* FIXME diagnostics: This should
388 be the location of the INIT. */
389 elocus,
390 init,
391 NULL_TREE);
392 }
393 gcc_assert (TREE_CODE (init) == MODIFY_EXPR);
394 gcc_assert (TREE_OPERAND (init, 0) == decl);
395
396 if (cond == NULL_TREE)
397 {
398 error_at (elocus, "missing controlling predicate");
399 fail = true;
400 }
401 else
402 {
403 bool cond_ok = false;
404
405 if (EXPR_HAS_LOCATION (cond))
406 elocus = EXPR_LOCATION (cond);
407
408 if (TREE_CODE (cond) == LT_EXPR
409 || TREE_CODE (cond) == LE_EXPR
410 || TREE_CODE (cond) == GT_EXPR
411 || TREE_CODE (cond) == GE_EXPR
412 || TREE_CODE (cond) == NE_EXPR
413 || TREE_CODE (cond) == EQ_EXPR)
414 {
415 tree op0 = TREE_OPERAND (cond, 0);
416 tree op1 = TREE_OPERAND (cond, 1);
417
418 /* 2.5.1. The comparison in the condition is computed in
419 the type of DECL, otherwise the behavior is undefined.
420
421 For example:
422 long n; int i;
423 i < n;
424
425 according to ISO will be evaluated as:
426 (long)i < n;
427
428 We want to force:
429 i < (int)n; */
430 if (TREE_CODE (op0) == NOP_EXPR
431 && decl == TREE_OPERAND (op0, 0))
432 {
433 TREE_OPERAND (cond, 0) = TREE_OPERAND (op0, 0);
434 TREE_OPERAND (cond, 1)
435 = fold_build1_loc (elocus, NOP_EXPR, TREE_TYPE (decl),
436 TREE_OPERAND (cond, 1));
437 }
438 else if (TREE_CODE (op1) == NOP_EXPR
439 && decl == TREE_OPERAND (op1, 0))
440 {
441 TREE_OPERAND (cond, 1) = TREE_OPERAND (op1, 0);
442 TREE_OPERAND (cond, 0)
443 = fold_build1_loc (elocus, NOP_EXPR, TREE_TYPE (decl),
444 TREE_OPERAND (cond, 0));
445 }
446
447 if (decl == TREE_OPERAND (cond, 0))
448 cond_ok = true;
449 else if (decl == TREE_OPERAND (cond, 1))
450 {
451 TREE_SET_CODE (cond,
452 swap_tree_comparison (TREE_CODE (cond)));
453 TREE_OPERAND (cond, 1) = TREE_OPERAND (cond, 0);
454 TREE_OPERAND (cond, 0) = decl;
455 cond_ok = true;
456 }
457
458 if (TREE_CODE (cond) == NE_EXPR
459 || TREE_CODE (cond) == EQ_EXPR)
460 {
461 if (!INTEGRAL_TYPE_P (TREE_TYPE (decl)))
462 cond_ok = false;
463 else if (operand_equal_p (TREE_OPERAND (cond, 1),
464 TYPE_MIN_VALUE (TREE_TYPE (decl)),
465 0))
466 TREE_SET_CODE (cond, TREE_CODE (cond) == NE_EXPR
467 ? GT_EXPR : LE_EXPR);
468 else if (operand_equal_p (TREE_OPERAND (cond, 1),
469 TYPE_MAX_VALUE (TREE_TYPE (decl)),
470 0))
471 TREE_SET_CODE (cond, TREE_CODE (cond) == NE_EXPR
472 ? LT_EXPR : GE_EXPR);
473 else
474 cond_ok = false;
475 }
476 }
477
478 if (!cond_ok)
479 {
480 error_at (elocus, "invalid controlling predicate");
481 fail = true;
482 }
483 }
484
485 if (incr == NULL_TREE)
486 {
487 error_at (elocus, "missing increment expression");
488 fail = true;
489 }
490 else
491 {
492 bool incr_ok = false;
493
494 if (EXPR_HAS_LOCATION (incr))
495 elocus = EXPR_LOCATION (incr);
496
497 /* Check all the valid increment expressions: v++, v--, ++v, --v,
498 v = v + incr, v = incr + v and v = v - incr. */
499 switch (TREE_CODE (incr))
500 {
501 case POSTINCREMENT_EXPR:
502 case PREINCREMENT_EXPR:
503 case POSTDECREMENT_EXPR:
504 case PREDECREMENT_EXPR:
505 if (TREE_OPERAND (incr, 0) != decl)
506 break;
507
508 incr_ok = true;
509 if (POINTER_TYPE_P (TREE_TYPE (decl))
510 && TREE_OPERAND (incr, 1))
511 {
512 tree t = fold_convert_loc (elocus,
513 sizetype, TREE_OPERAND (incr, 1));
514
515 if (TREE_CODE (incr) == POSTDECREMENT_EXPR
516 || TREE_CODE (incr) == PREDECREMENT_EXPR)
517 t = fold_build1_loc (elocus, NEGATE_EXPR, sizetype, t);
518 t = fold_build_pointer_plus (decl, t);
519 incr = build2 (MODIFY_EXPR, void_type_node, decl, t);
520 }
521 break;
522
523 case MODIFY_EXPR:
524 if (TREE_OPERAND (incr, 0) != decl)
525 break;
526 if (TREE_OPERAND (incr, 1) == decl)
527 break;
528 if (TREE_CODE (TREE_OPERAND (incr, 1)) == PLUS_EXPR
529 && (TREE_OPERAND (TREE_OPERAND (incr, 1), 0) == decl
530 || TREE_OPERAND (TREE_OPERAND (incr, 1), 1) == decl))
531 incr_ok = true;
532 else if ((TREE_CODE (TREE_OPERAND (incr, 1)) == MINUS_EXPR
533 || (TREE_CODE (TREE_OPERAND (incr, 1))
534 == POINTER_PLUS_EXPR))
535 && TREE_OPERAND (TREE_OPERAND (incr, 1), 0) == decl)
536 incr_ok = true;
537 else
538 {
539 tree t = check_omp_for_incr_expr (elocus,
540 TREE_OPERAND (incr, 1),
541 decl);
542 if (t != error_mark_node)
543 {
544 incr_ok = true;
545 t = build2 (PLUS_EXPR, TREE_TYPE (decl), decl, t);
546 incr = build2 (MODIFY_EXPR, void_type_node, decl, t);
547 }
548 }
549 break;
550
551 default:
552 break;
553 }
554 if (!incr_ok)
555 {
556 error_at (elocus, "invalid increment expression");
557 fail = true;
558 }
559 }
560
561 TREE_VEC_ELT (initv, i) = init;
562 TREE_VEC_ELT (incrv, i) = incr;
563 }
564
565 if (fail)
566 return NULL;
567 else
568 {
569 tree t = make_node (OMP_FOR);
570
571 TREE_TYPE (t) = void_type_node;
572 OMP_FOR_INIT (t) = initv;
573 OMP_FOR_COND (t) = condv;
574 OMP_FOR_INCR (t) = incrv;
575 OMP_FOR_BODY (t) = body;
576 OMP_FOR_PRE_BODY (t) = pre_body;
577
578 SET_EXPR_LOCATION (t, locus);
579 return add_stmt (t);
580 }
581 }
582
583
584 /* Divide CLAUSES into two lists: those that apply to a parallel
585 construct, and those that apply to a work-sharing construct. Place
586 the results in *PAR_CLAUSES and *WS_CLAUSES respectively. In
587 addition, add a nowait clause to the work-sharing list. LOC is the
588 location of the OMP_PARALLEL*. */
589
590 void
c_split_parallel_clauses(location_t loc,tree clauses,tree * par_clauses,tree * ws_clauses)591 c_split_parallel_clauses (location_t loc, tree clauses,
592 tree *par_clauses, tree *ws_clauses)
593 {
594 tree next;
595
596 *par_clauses = NULL;
597 *ws_clauses = build_omp_clause (loc, OMP_CLAUSE_NOWAIT);
598
599 for (; clauses ; clauses = next)
600 {
601 next = OMP_CLAUSE_CHAIN (clauses);
602
603 switch (OMP_CLAUSE_CODE (clauses))
604 {
605 case OMP_CLAUSE_PRIVATE:
606 case OMP_CLAUSE_SHARED:
607 case OMP_CLAUSE_FIRSTPRIVATE:
608 case OMP_CLAUSE_LASTPRIVATE:
609 case OMP_CLAUSE_REDUCTION:
610 case OMP_CLAUSE_COPYIN:
611 case OMP_CLAUSE_IF:
612 case OMP_CLAUSE_NUM_THREADS:
613 case OMP_CLAUSE_DEFAULT:
614 OMP_CLAUSE_CHAIN (clauses) = *par_clauses;
615 *par_clauses = clauses;
616 break;
617
618 case OMP_CLAUSE_SCHEDULE:
619 case OMP_CLAUSE_ORDERED:
620 case OMP_CLAUSE_COLLAPSE:
621 OMP_CLAUSE_CHAIN (clauses) = *ws_clauses;
622 *ws_clauses = clauses;
623 break;
624
625 default:
626 gcc_unreachable ();
627 }
628 }
629 }
630
631 /* True if OpenMP sharing attribute of DECL is predetermined. */
632
633 enum omp_clause_default_kind
c_omp_predetermined_sharing(tree decl)634 c_omp_predetermined_sharing (tree decl)
635 {
636 /* Variables with const-qualified type having no mutable member
637 are predetermined shared. */
638 if (TREE_READONLY (decl))
639 return OMP_CLAUSE_DEFAULT_SHARED;
640
641 return OMP_CLAUSE_DEFAULT_UNSPECIFIED;
642 }
643