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)
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/>. */
26 #include "coretypes.h"
30 /* Helper function for c_check_cilk_loop.
32 Validate the increment in a _Cilk_for construct or a <#pragma simd>
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. */
42 c_check_cilk_loop_incr (location_t loc
, tree decl
, tree incr
)
44 if (EXPR_HAS_LOCATION (incr
))
45 loc
= EXPR_LOCATION (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
)
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
);
81 if (TREE_OPERAND (incr
, 0) != decl
)
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
)))
90 else if (TREE_CODE (rhs
) == MINUS_EXPR
91 && TREE_OPERAND (rhs
, 0) == decl
92 && INTEGRAL_TYPE_P (TREE_TYPE (rhs
)))
94 // Otherwise fail because only PLUS_EXPR and MINUS_EXPR are
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
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. */
116 c_validate_cilk_plus_loop (tree
*tp
, int *walk_subtrees
, void *data
)
121 bool *valid
= (bool *) data
;
123 switch (TREE_CODE (*tp
))
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");
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");
171 /* Validate the body of a _Cilk_for construct or a <#pragma simd> for
174 Returns true if there were no errors, false otherwise. */
177 c_check_cilk_loop_body (tree body
)
180 walk_tree (&body
, c_validate_cilk_plus_loop
, (void *) &valid
, NULL
);
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. */
200 c_check_cilk_loop (location_t loc
, tree decl
, tree cond
, tree
*incrp
,
201 tree body
, bool scan_body
)
205 if (decl
== error_mark_node
206 || cond
== error_mark_node
207 || incr
== error_mark_node
208 || body
== error_mark_node
)
211 /* Validate the initialization. */
212 gcc_assert (decl
!= NULL
);
213 if (TREE_THIS_VOLATILE (decl
))
215 error_at (loc
, "induction variable cannot be volatile");
218 if (DECL_EXTERNAL (decl
))
220 error_at (loc
, "induction variable cannot be extern");
223 if (TREE_STATIC (decl
))
225 error_at (loc
, "induction variable cannot be static");
228 if (DECL_REGISTER (decl
))
230 error_at (loc
, "induction variable cannot be declared register");
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
));
241 /* Validate the condition. */
244 error_at (loc
, "missing condition");
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))
260 else if (decl
== TREE_OPERAND (cond
, 1))
262 /* Canonicalize the comparison so the DECL is on the LHS. */
264 swap_tree_comparison (TREE_CODE (cond
)));
265 TREE_OPERAND (cond
, 1) = TREE_OPERAND (cond
, 0);
266 TREE_OPERAND (cond
, 0) = decl
;
272 error_at (loc
, "invalid controlling predicate");
276 /* Validate and canonicalize the increment. */
277 incr
= c_check_cilk_loop_incr (loc
, decl
, incr
);
278 if (incr
== error_mark_node
)
282 if (scan_body
&& !c_check_cilk_loop_body (body
))
288 /* Adjust any clauses to match the requirements for OpenMP. */
291 adjust_clauses_for_omp (tree clauses
)
296 /* Validate and emit code for the FOR loop following a #<pragma simd>
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. */
311 c_finish_cilk_simd_loop (location_t loc
,
313 tree init
, tree cond
, tree incr
,
320 if (!c_check_cilk_loop (loc
, decl
, cond
, &incr
, body
, scan_body
))
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. */
327 rhs_loc
= DECL_SOURCE_LOCATION (decl
);
329 init
= DECL_INITIAL (decl
);
332 error_at (rhs_loc
, "%qE is not initialized", decl
);
333 init
= integer_zero_node
;
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
);
367 /* Validate and emit code for <#pragma simd> clauses. */
370 c_finish_cilk_clauses (tree clauses
)
372 for (tree c
= clauses
; c
; c
= OMP_CLAUSE_CHAIN (c
))
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
))
383 enum omp_clause_code code
= OMP_CLAUSE_CODE (c2
);
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
:
394 case OMP_CLAUSE_SAFELEN
:
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
);