Cilk Plus #pragma simd iteration with Jason.
[official-gcc.git] / gcc / c-family / c-cilkplus.c
blob7b80c3f017b481dc35eb3b94d7231f570b1f6932
1 /* This file contains routines to construct and validate Cilk Plus
2 constructs within the C and C++ front ends.
4 Copyright (C) 2011-2013 Free Software Foundation, Inc.
5 Contributed by Balaji V. Iyer <balaji.v.iyer@intel.com>,
6 Aldy Hernandez <aldyh@redhat.com>.
8 This file is part of GCC.
10 GCC is free software; you can redistribute it and/or modify it
11 under the terms of the GNU General Public License as published by
12 the Free Software Foundation; either version 3, or (at your option)
13 any later version.
15 GCC is distributed in the hope that it will be useful, but
16 WITHOUT ANY WARRANTY; without even the implied warranty of
17 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
18 General Public License for more details.
20 You should have received a copy of the GNU General Public License
21 along with GCC; see the file COPYING3. If not see
22 <http://www.gnu.org/licenses/>. */
24 #include "config.h"
25 #include "system.h"
26 #include "coretypes.h"
27 #include "tree.h"
28 #include "c-common.h"
30 /* Helper function for c_check_cilk_loop.
32 Validate the increment in a _Cilk_for construct or a <#pragma simd>
33 for loop.
35 LOC is the location of the `for' keyword. DECL is the induction
36 variable. INCR is the original increment expression.
38 Returns the canonicalized increment expression for an OMP_FOR_INCR.
39 If there is a validation error, returns error_mark_node. */
41 static tree
42 c_check_cilk_loop_incr (location_t loc, tree decl, tree incr)
44 if (EXPR_HAS_LOCATION (incr))
45 loc = EXPR_LOCATION (incr);
47 if (!incr)
49 error_at (loc, "missing increment");
50 return error_mark_node;
53 switch (TREE_CODE (incr))
55 case POSTINCREMENT_EXPR:
56 case PREINCREMENT_EXPR:
57 case POSTDECREMENT_EXPR:
58 case PREDECREMENT_EXPR:
59 if (TREE_OPERAND (incr, 0) != decl)
60 break;
62 // Bah... canonicalize into whatever OMP_FOR_INCR needs.
63 if (POINTER_TYPE_P (TREE_TYPE (decl))
64 && TREE_OPERAND (incr, 1))
66 tree t = fold_convert_loc (loc,
67 sizetype, TREE_OPERAND (incr, 1));
69 if (TREE_CODE (incr) == POSTDECREMENT_EXPR
70 || TREE_CODE (incr) == PREDECREMENT_EXPR)
71 t = fold_build1_loc (loc, NEGATE_EXPR, sizetype, t);
72 t = fold_build_pointer_plus (decl, t);
73 incr = build2 (MODIFY_EXPR, void_type_node, decl, t);
75 return incr;
77 case MODIFY_EXPR:
79 tree rhs;
81 if (TREE_OPERAND (incr, 0) != decl)
82 break;
84 rhs = TREE_OPERAND (incr, 1);
85 if (TREE_CODE (rhs) == PLUS_EXPR
86 && (TREE_OPERAND (rhs, 0) == decl
87 || TREE_OPERAND (rhs, 1) == decl)
88 && INTEGRAL_TYPE_P (TREE_TYPE (rhs)))
89 return incr;
90 else if (TREE_CODE (rhs) == MINUS_EXPR
91 && TREE_OPERAND (rhs, 0) == decl
92 && INTEGRAL_TYPE_P (TREE_TYPE (rhs)))
93 return incr;
94 // Otherwise fail because only PLUS_EXPR and MINUS_EXPR are
95 // allowed.
96 break;
99 default:
100 break;
103 error_at (loc, "invalid increment expression");
104 return error_mark_node;
107 /* Callback for walk_tree to validate the body of a pragma simd loop
108 or _cilk_for loop.
110 This function is passed in as a function pointer to walk_tree. *TP is
111 the current tree pointer, *WALK_SUBTREES is set to 0 by this function if
112 recursing into TP's subtrees is unnecessary. *DATA is a bool variable that
113 is set to false if an error has occured. */
115 tree
116 c_validate_cilk_plus_loop (tree *tp, int *walk_subtrees, void *data)
118 if (!tp || !*tp)
119 return NULL_TREE;
121 bool *valid = (bool *) data;
123 switch (TREE_CODE (*tp))
125 case CALL_EXPR:
127 tree fndecl = CALL_EXPR_FN (*tp);
129 if (TREE_CODE (fndecl) == ADDR_EXPR)
130 fndecl = TREE_OPERAND (fndecl, 0);
131 if (TREE_CODE (fndecl) == FUNCTION_DECL)
133 if (setjmp_call_p (fndecl))
135 error_at (EXPR_LOCATION (*tp),
136 "calls to setjmp are not allowed within loops "
137 "annotated with #pragma simd");
138 *valid = false;
139 *walk_subtrees = 0;
142 break;
145 case OMP_PARALLEL:
146 case OMP_TASK:
147 case OMP_FOR:
148 case OMP_SIMD:
149 case OMP_SECTIONS:
150 case OMP_SINGLE:
151 case OMP_SECTION:
152 case OMP_MASTER:
153 case OMP_ORDERED:
154 case OMP_CRITICAL:
155 case OMP_ATOMIC:
156 case OMP_ATOMIC_READ:
157 case OMP_ATOMIC_CAPTURE_OLD:
158 case OMP_ATOMIC_CAPTURE_NEW:
159 error_at (EXPR_LOCATION (*tp), "OpenMP statements are not allowed "
160 "within loops annotated with #pragma simd");
161 *valid = false;
162 *walk_subtrees = 0;
163 break;
165 default:
166 break;
168 return NULL_TREE;
171 /* Validate the body of a _Cilk_for construct or a <#pragma simd> for
172 loop.
174 Returns true if there were no errors, false otherwise. */
176 static bool
177 c_check_cilk_loop_body (tree body)
179 bool valid = true;
180 walk_tree (&body, c_validate_cilk_plus_loop, (void *) &valid, NULL);
181 return valid;
184 /* Validate a _Cilk_for construct (or a #pragma simd for loop, which
185 has the same syntactic restrictions).
187 Returns TRUE if there were no errors, FALSE otherwise.
189 LOC is the location of the for.
190 DECL is the controlling variable.
191 COND is the condition.
193 INCRP is a pointer the increment expression (in case the increment
194 needs to be canonicalized).
196 BODY is the body of the LOOP.
197 SCAN_BODY is true if the body must be checked. */
199 static bool
200 c_check_cilk_loop (location_t loc, tree decl, tree cond, tree *incrp,
201 tree body, bool scan_body)
203 tree incr = *incrp;
205 if (decl == error_mark_node
206 || cond == error_mark_node
207 || incr == error_mark_node
208 || body == error_mark_node)
209 return false;
211 /* Validate the initialization. */
212 gcc_assert (decl != NULL);
213 if (TREE_THIS_VOLATILE (decl))
215 error_at (loc, "induction variable cannot be volatile");
216 return false;
218 if (DECL_EXTERNAL (decl))
220 error_at (loc, "induction variable cannot be extern");
221 return false;
223 if (TREE_STATIC (decl))
225 error_at (loc, "induction variable cannot be static");
226 return false;
228 if (DECL_REGISTER (decl))
230 error_at (loc, "induction variable cannot be declared register");
231 return false;
233 if (!INTEGRAL_TYPE_P (TREE_TYPE (decl))
234 && !POINTER_TYPE_P (TREE_TYPE (decl)))
236 error_at (loc, "induction variable must be of integral "
237 "or pointer type (have %qT)", TREE_TYPE (decl));
238 return false;
241 /* Validate the condition. */
242 if (!cond)
244 error_at (loc, "missing condition");
245 return false;
247 bool cond_ok = false;
248 if (TREE_CODE (cond) == NE_EXPR
249 || TREE_CODE (cond) == LT_EXPR
250 || TREE_CODE (cond) == LE_EXPR
251 || TREE_CODE (cond) == GT_EXPR
252 || TREE_CODE (cond) == GE_EXPR)
254 /* Comparison must either be:
255 DECL <comparison_operator> EXPR
256 EXPR <comparison_operator> DECL
258 if (decl == TREE_OPERAND (cond, 0))
259 cond_ok = true;
260 else if (decl == TREE_OPERAND (cond, 1))
262 /* Canonicalize the comparison so the DECL is on the LHS. */
263 TREE_SET_CODE (cond,
264 swap_tree_comparison (TREE_CODE (cond)));
265 TREE_OPERAND (cond, 1) = TREE_OPERAND (cond, 0);
266 TREE_OPERAND (cond, 0) = decl;
267 cond_ok = true;
270 if (!cond_ok)
272 error_at (loc, "invalid controlling predicate");
273 return false;
276 /* Validate and canonicalize the increment. */
277 incr = c_check_cilk_loop_incr (loc, decl, incr);
278 if (incr == error_mark_node)
279 return false;
280 *incrp = incr;
282 if (scan_body && !c_check_cilk_loop_body (body))
283 return false;
285 return true;
288 /* Adjust any clauses to match the requirements for OpenMP. */
290 static tree
291 adjust_clauses_for_omp (tree clauses)
293 return clauses;
296 /* Validate and emit code for the FOR loop following a #<pragma simd>
297 construct.
299 LOC is the location of the location of the FOR.
300 DECL is the iteration variable.
301 INIT is the initialization expression.
302 COND is the controlling predicate.
303 INCR is the increment expression.
304 BODY is the body of the loop.
305 CLAUSES are the clauses associated with the pragma simd loop.
306 SCAN_BODY is true if the body of the loop must be verified.
308 Returns the generated statement. */
310 tree
311 c_finish_cilk_simd_loop (location_t loc,
312 tree decl,
313 tree init, tree cond, tree incr,
314 tree body,
315 tree clauses,
316 bool scan_body)
318 location_t rhs_loc;
320 if (!c_check_cilk_loop (loc, decl, cond, &incr, body, scan_body))
321 return NULL;
323 /* In the case of "for (int i = 0...)", init will be a decl. It should
324 have a DECL_INITIAL that we can turn into an assignment. */
325 if (init == decl)
327 rhs_loc = DECL_SOURCE_LOCATION (decl);
329 init = DECL_INITIAL (decl);
330 if (init == NULL)
332 error_at (rhs_loc, "%qE is not initialized", decl);
333 init = integer_zero_node;
334 return NULL;
337 init = build2 (INIT_EXPR, TREE_TYPE (decl), decl, init);
338 DECL_INITIAL (decl) = NULL;
341 // The C++ parser just gives us the rhs.
342 if (TREE_CODE (init) != MODIFY_EXPR)
343 init = build2 (INIT_EXPR, TREE_TYPE (decl), decl, init);
345 gcc_assert (TREE_OPERAND (init, 0) == decl);
347 tree initv = make_tree_vec (1);
348 tree condv = make_tree_vec (1);
349 tree incrv = make_tree_vec (1);
350 TREE_VEC_ELT (initv, 0) = init;
351 TREE_VEC_ELT (condv, 0) = cond;
352 TREE_VEC_ELT (incrv, 0) = incr;
354 tree t = make_node (CILK_SIMD);
355 TREE_TYPE (t) = void_type_node;
356 OMP_FOR_INIT (t) = initv;
357 OMP_FOR_COND (t) = condv;
358 OMP_FOR_INCR (t) = incrv;
359 OMP_FOR_BODY (t) = body;
360 OMP_FOR_PRE_BODY (t) = NULL;
361 OMP_FOR_CLAUSES (t) = adjust_clauses_for_omp (clauses);
363 SET_EXPR_LOCATION (t, loc);
364 return add_stmt (t);
367 /* Validate and emit code for <#pragma simd> clauses. */
369 tree
370 c_finish_cilk_clauses (tree clauses)
372 for (tree c = clauses; c; c = OMP_CLAUSE_CHAIN (c))
374 tree prev = clauses;
376 /* If a variable appears in a linear clause it cannot appear in
377 any other OMP clause. */
378 if (OMP_CLAUSE_CODE (c) == OMP_CLAUSE_LINEAR)
379 for (tree c2 = clauses; c2; c2 = OMP_CLAUSE_CHAIN (c2))
381 if (c == c2)
382 continue;
383 enum omp_clause_code code = OMP_CLAUSE_CODE (c2);
385 switch (code)
387 case OMP_CLAUSE_LINEAR:
388 case OMP_CLAUSE_PRIVATE:
389 case OMP_CLAUSE_FIRSTPRIVATE:
390 case OMP_CLAUSE_LASTPRIVATE:
391 case OMP_CLAUSE_REDUCTION:
392 break;
394 case OMP_CLAUSE_SAFELEN:
395 goto next;
397 default:
398 gcc_unreachable ();
401 if (OMP_CLAUSE_DECL (c) == OMP_CLAUSE_DECL (c2))
403 error_at (OMP_CLAUSE_LOCATION (c2),
404 "variable appears in more than one clause");
405 inform (OMP_CLAUSE_LOCATION (c),
406 "other clause defined here");
407 // Remove problematic clauses.
408 OMP_CLAUSE_CHAIN (prev) = OMP_CLAUSE_CHAIN (c2);
410 next:
411 prev = c2;
415 return clauses;