]>
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 | ||
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 | |
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 | |
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 | |
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 | |
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. */ | |
86 | ||
87 | void | |
88 | c_finish_omp_atomic (enum tree_code code, tree lhs, tree rhs) | |
89 | { | |
90 | tree x, type, addr; | |
91 | ||
92 | if (lhs == error_mark_node || rhs == error_mark_node) | |
93 | return; | |
94 | ||
95 | /* ??? According to one reading of the OpenMP spec, complex type are | |
96 | supported, but there are no atomic stores for any architecture. | |
97 | But at least icc 9.0 doesn't support complex types here either. | |
98 | And lets not even talk about vector types... */ | |
99 | type = TREE_TYPE (lhs); | |
100 | if (!INTEGRAL_TYPE_P (type) | |
101 | && !POINTER_TYPE_P (type) | |
102 | && !SCALAR_FLOAT_TYPE_P (type)) | |
103 | { | |
104 | error ("invalid expression type for %<#pragma omp atomic%>"); | |
105 | return; | |
106 | } | |
107 | ||
108 | /* ??? Validate that rhs does not overlap lhs. */ | |
109 | ||
110 | /* Take and save the address of the lhs. From then on we'll reference it | |
111 | via indirection. */ | |
112 | addr = build_unary_op (ADDR_EXPR, lhs, 0); | |
113 | if (addr == error_mark_node) | |
114 | return; | |
115 | addr = save_expr (addr); | |
116 | lhs = build_indirect_ref (addr, NULL); | |
117 | ||
118 | /* There are lots of warnings, errors, and conversions that need to happen | |
119 | in the course of interpreting a statement. Use the normal mechanisms | |
120 | to do this, and then take it apart again. */ | |
121 | x = build_modify_expr (lhs, code, rhs); | |
122 | if (x == error_mark_node) | |
123 | return; | |
124 | gcc_assert (TREE_CODE (x) == MODIFY_EXPR); | |
125 | rhs = TREE_OPERAND (x, 1); | |
126 | ||
127 | /* Punt the actual generation of atomic operations to common code. */ | |
128 | add_stmt (build2 (OMP_ATOMIC, void_type_node, addr, rhs)); | |
129 | } | |
130 | ||
131 | ||
132 | /* Complete a #pragma omp flush construct. We don't do anything with the | |
133 | variable list that the syntax allows. */ | |
134 | ||
135 | void | |
136 | c_finish_omp_flush (void) | |
137 | { | |
138 | tree x; | |
139 | ||
140 | x = built_in_decls[BUILT_IN_SYNCHRONIZE]; | |
141 | x = build_function_call_expr (x, NULL); | |
142 | add_stmt (x); | |
143 | } | |
144 | ||
145 | ||
146 | /* Check and canonicalize #pragma omp for increment expression. | |
147 | Helper function for c_finish_omp_for. */ | |
148 | ||
149 | static tree | |
150 | check_omp_for_incr_expr (tree exp, tree decl) | |
151 | { | |
152 | tree t; | |
153 | ||
154 | if (!INTEGRAL_TYPE_P (TREE_TYPE (exp)) | |
155 | || TYPE_PRECISION (TREE_TYPE (exp)) < TYPE_PRECISION (TREE_TYPE (decl))) | |
156 | return error_mark_node; | |
157 | ||
158 | if (exp == decl) | |
159 | return build_int_cst (TREE_TYPE (exp), 0); | |
160 | ||
161 | switch (TREE_CODE (exp)) | |
162 | { | |
163 | case NOP_EXPR: | |
164 | t = check_omp_for_incr_expr (TREE_OPERAND (exp, 0), decl); | |
165 | if (t != error_mark_node) | |
166 | return fold_convert (TREE_TYPE (exp), t); | |
167 | break; | |
168 | case MINUS_EXPR: | |
169 | t = check_omp_for_incr_expr (TREE_OPERAND (exp, 0), decl); | |
170 | if (t != error_mark_node) | |
171 | return fold_build2 (MINUS_EXPR, TREE_TYPE (exp), t, TREE_OPERAND (exp, 1)); | |
172 | break; | |
173 | case PLUS_EXPR: | |
174 | t = check_omp_for_incr_expr (TREE_OPERAND (exp, 0), decl); | |
175 | if (t != error_mark_node) | |
176 | return fold_build2 (PLUS_EXPR, TREE_TYPE (exp), t, TREE_OPERAND (exp, 1)); | |
177 | t = check_omp_for_incr_expr (TREE_OPERAND (exp, 1), decl); | |
178 | if (t != error_mark_node) | |
179 | return fold_build2 (PLUS_EXPR, TREE_TYPE (exp), TREE_OPERAND (exp, 0), t); | |
180 | break; | |
181 | default: | |
182 | break; | |
183 | } | |
184 | ||
185 | return error_mark_node; | |
186 | } | |
187 | ||
188 | /* Validate and emit code for the OpenMP directive #pragma omp for. | |
189 | INIT, COND, INCR, BODY and PRE_BODY are the five basic elements | |
190 | of the loop (initialization expression, controlling predicate, increment | |
191 | expression, body of the loop and statements to go before the loop). | |
192 | DECL is the iteration variable. */ | |
193 | ||
194 | tree | |
195 | c_finish_omp_for (location_t locus, tree decl, tree init, tree cond, | |
196 | tree incr, tree body, tree pre_body) | |
197 | { | |
198 | location_t elocus = locus; | |
199 | bool fail = false; | |
200 | ||
201 | if (EXPR_HAS_LOCATION (init)) | |
202 | elocus = EXPR_LOCATION (init); | |
203 | ||
204 | /* Validate the iteration variable. */ | |
205 | if (!INTEGRAL_TYPE_P (TREE_TYPE (decl))) | |
206 | { | |
207 | error ("%Hinvalid type for iteration variable %qE", &elocus, decl); | |
208 | fail = true; | |
209 | } | |
210 | if (TYPE_UNSIGNED (TREE_TYPE (decl))) | |
211 | warning (0, "%Hiteration variable %qE is unsigned", &elocus, decl); | |
212 | ||
213 | /* In the case of "for (int i = 0...)", init will be a decl. It should | |
214 | have a DECL_INITIAL that we can turn into an assignment. */ | |
215 | if (init == decl) | |
216 | { | |
217 | elocus = DECL_SOURCE_LOCATION (decl); | |
218 | ||
219 | init = DECL_INITIAL (decl); | |
220 | if (init == NULL) | |
221 | { | |
222 | error ("%H%qE is not initialized", &elocus, decl); | |
223 | init = integer_zero_node; | |
224 | fail = true; | |
225 | } | |
226 | ||
227 | init = build_modify_expr (decl, NOP_EXPR, init); | |
228 | SET_EXPR_LOCATION (init, elocus); | |
229 | } | |
230 | gcc_assert (TREE_CODE (init) == MODIFY_EXPR); | |
231 | gcc_assert (TREE_OPERAND (init, 0) == decl); | |
232 | ||
233 | if (cond == NULL_TREE) | |
234 | { | |
235 | error ("%Hmissing controlling predicate", &elocus); | |
236 | fail = true; | |
237 | } | |
238 | else | |
239 | { | |
240 | bool cond_ok = false; | |
241 | ||
242 | if (EXPR_HAS_LOCATION (cond)) | |
243 | elocus = EXPR_LOCATION (cond); | |
244 | ||
245 | if (TREE_CODE (cond) == LT_EXPR | |
246 | || TREE_CODE (cond) == LE_EXPR | |
247 | || TREE_CODE (cond) == GT_EXPR | |
248 | || TREE_CODE (cond) == GE_EXPR) | |
249 | { | |
250 | tree op0 = TREE_OPERAND (cond, 0); | |
251 | tree op1 = TREE_OPERAND (cond, 1); | |
252 | ||
253 | /* 2.5.1. The comparison in the condition is computed in the type | |
254 | of DECL, otherwise the behavior is undefined. | |
255 | ||
256 | For example: | |
257 | long n; int i; | |
258 | i < n; | |
259 | ||
260 | according to ISO will be evaluated as: | |
261 | (long)i < n; | |
262 | ||
263 | We want to force: | |
264 | i < (int)n; */ | |
265 | if (TREE_CODE (op0) == NOP_EXPR | |
266 | && decl == TREE_OPERAND (op0, 0)) | |
267 | { | |
268 | TREE_OPERAND (cond, 0) = TREE_OPERAND (op0, 0); | |
269 | TREE_OPERAND (cond, 1) = fold_build1 (NOP_EXPR, TREE_TYPE (decl), | |
270 | TREE_OPERAND (cond, 1)); | |
271 | } | |
272 | else if (TREE_CODE (op1) == NOP_EXPR | |
273 | && decl == TREE_OPERAND (op1, 0)) | |
274 | { | |
275 | TREE_OPERAND (cond, 1) = TREE_OPERAND (op1, 0); | |
276 | TREE_OPERAND (cond, 0) = fold_build1 (NOP_EXPR, TREE_TYPE (decl), | |
277 | TREE_OPERAND (cond, 0)); | |
278 | } | |
279 | ||
280 | if (decl == TREE_OPERAND (cond, 0)) | |
281 | cond_ok = true; | |
282 | else if (decl == TREE_OPERAND (cond, 1)) | |
283 | { | |
284 | TREE_SET_CODE (cond, swap_tree_comparison (TREE_CODE (cond))); | |
285 | TREE_OPERAND (cond, 1) = TREE_OPERAND (cond, 0); | |
286 | TREE_OPERAND (cond, 0) = decl; | |
287 | cond_ok = true; | |
288 | } | |
289 | } | |
290 | ||
291 | if (!cond_ok) | |
292 | { | |
293 | error ("%Hinvalid controlling predicate", &elocus); | |
294 | fail = true; | |
295 | } | |
296 | } | |
297 | ||
298 | if (incr == NULL_TREE) | |
299 | { | |
300 | error ("%Hmissing increment expression", &elocus); | |
301 | fail = true; | |
302 | } | |
303 | else | |
304 | { | |
305 | bool incr_ok = false; | |
306 | ||
307 | if (EXPR_HAS_LOCATION (incr)) | |
308 | elocus = EXPR_LOCATION (incr); | |
309 | ||
310 | /* Check all the valid increment expressions: v++, v--, ++v, --v, | |
311 | v = v + incr, v = incr + v and v = v - incr. */ | |
312 | switch (TREE_CODE (incr)) | |
313 | { | |
314 | case POSTINCREMENT_EXPR: | |
315 | case PREINCREMENT_EXPR: | |
316 | case POSTDECREMENT_EXPR: | |
317 | case PREDECREMENT_EXPR: | |
318 | incr_ok = (TREE_OPERAND (incr, 0) == decl); | |
319 | break; | |
320 | ||
321 | case MODIFY_EXPR: | |
322 | if (TREE_OPERAND (incr, 0) != decl) | |
323 | break; | |
324 | if (TREE_OPERAND (incr, 1) == decl) | |
325 | break; | |
326 | if (TREE_CODE (TREE_OPERAND (incr, 1)) == PLUS_EXPR | |
327 | && (TREE_OPERAND (TREE_OPERAND (incr, 1), 0) == decl | |
328 | || TREE_OPERAND (TREE_OPERAND (incr, 1), 1) == decl)) | |
329 | incr_ok = true; | |
330 | else if (TREE_CODE (TREE_OPERAND (incr, 1)) == MINUS_EXPR | |
331 | && TREE_OPERAND (TREE_OPERAND (incr, 1), 0) == decl) | |
332 | incr_ok = true; | |
333 | else | |
334 | { | |
335 | tree t = check_omp_for_incr_expr (TREE_OPERAND (incr, 1), decl); | |
336 | if (t != error_mark_node) | |
337 | { | |
338 | incr_ok = true; | |
339 | t = build2 (PLUS_EXPR, TREE_TYPE (decl), decl, t); | |
340 | incr = build2 (MODIFY_EXPR, void_type_node, decl, t); | |
341 | } | |
342 | } | |
343 | break; | |
344 | ||
345 | default: | |
346 | break; | |
347 | } | |
348 | if (!incr_ok) | |
349 | { | |
350 | error ("%Hinvalid increment expression", &elocus); | |
351 | fail = true; | |
352 | } | |
353 | } | |
354 | ||
355 | if (fail) | |
356 | return NULL; | |
357 | else | |
358 | { | |
359 | tree t = make_node (OMP_FOR); | |
360 | ||
361 | TREE_TYPE (t) = void_type_node; | |
362 | OMP_FOR_INIT (t) = init; | |
363 | OMP_FOR_COND (t) = cond; | |
364 | OMP_FOR_INCR (t) = incr; | |
365 | OMP_FOR_BODY (t) = body; | |
366 | OMP_FOR_PRE_BODY (t) = pre_body; | |
367 | ||
368 | SET_EXPR_LOCATION (t, locus); | |
369 | return add_stmt (t); | |
370 | } | |
371 | } | |
372 | ||
373 | ||
374 | /* Divide CLAUSES into two lists: those that apply to a parallel construct, | |
375 | and those that apply to a work-sharing construct. Place the results in | |
376 | *PAR_CLAUSES and *WS_CLAUSES respectively. In addition, add a nowait | |
377 | clause to the work-sharing list. */ | |
378 | ||
379 | void | |
380 | c_split_parallel_clauses (tree clauses, tree *par_clauses, tree *ws_clauses) | |
381 | { | |
382 | tree next; | |
383 | ||
384 | *par_clauses = NULL; | |
aaf46ef9 | 385 | *ws_clauses = build_omp_clause (OMP_CLAUSE_NOWAIT); |
953ff289 DN |
386 | |
387 | for (; clauses ; clauses = next) | |
388 | { | |
389 | next = OMP_CLAUSE_CHAIN (clauses); | |
390 | ||
aaf46ef9 | 391 | switch (OMP_CLAUSE_CODE (clauses)) |
953ff289 DN |
392 | { |
393 | case OMP_CLAUSE_PRIVATE: | |
394 | case OMP_CLAUSE_SHARED: | |
395 | case OMP_CLAUSE_FIRSTPRIVATE: | |
396 | case OMP_CLAUSE_LASTPRIVATE: | |
397 | case OMP_CLAUSE_REDUCTION: | |
398 | case OMP_CLAUSE_COPYIN: | |
399 | case OMP_CLAUSE_IF: | |
400 | case OMP_CLAUSE_NUM_THREADS: | |
401 | case OMP_CLAUSE_DEFAULT: | |
402 | OMP_CLAUSE_CHAIN (clauses) = *par_clauses; | |
403 | *par_clauses = clauses; | |
404 | break; | |
405 | ||
406 | case OMP_CLAUSE_SCHEDULE: | |
407 | case OMP_CLAUSE_ORDERED: | |
408 | OMP_CLAUSE_CHAIN (clauses) = *ws_clauses; | |
409 | *ws_clauses = clauses; | |
410 | break; | |
411 | ||
412 | default: | |
413 | gcc_unreachable (); | |
414 | } | |
415 | } | |
416 | } | |
417 | ||
418 | /* True if OpenMP sharing attribute of DECL is predetermined. */ | |
419 | ||
420 | enum omp_clause_default_kind | |
421 | c_omp_predetermined_sharing (tree decl) | |
422 | { | |
423 | /* Variables with const-qualified type having no mutable member | |
424 | are predetermined shared. */ | |
425 | if (TREE_READONLY (decl)) | |
426 | return OMP_CLAUSE_DEFAULT_SHARED; | |
427 | ||
428 | return OMP_CLAUSE_DEFAULT_UNSPECIFIED; | |
429 | } |