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