diff options
author | Aldy Hernandez <aldyh@redhat.com> | 2013-07-05 15:08:07 -0700 |
---|---|---|
committer | Aldy Hernandez <aldyh@redhat.com> | 2013-07-09 08:10:06 -0700 |
commit | 564a9fa14ef114c12a4c070a92abf9474ee04298 (patch) | |
tree | 9137dbc1c5d38b2d4e7a3f308ac8ec46081cbd2e | |
parent | c237e9357ba6ee40db59555cfff76bfaa8b5a8a0 (diff) | |
download | gcc-564a9fa14ef114c12a4c070a92abf9474ee04298.tar.gz |
Cilk Plus <#pragma simd> implementation on top of OMP_SIMD.
45 files changed, 2309 insertions, 25 deletions
diff --git a/gcc/ChangeLog.cilkplus b/gcc/ChangeLog.cilkplus new file mode 100644 index 00000000000..bfcd59c042c --- /dev/null +++ b/gcc/ChangeLog.cilkplus @@ -0,0 +1,47 @@ +2013-06-20 Aldy Hernandez <aldyh@redhat.com> + Balaji V. Iyer <balaji.v.iyer@intel.com> + + * Makefile.in (C_COMMON_OBJS): Depend on c-family/c-cilkplus.o. + (c-cilkplus.o): New dependency. + * omp-low.c (extract_omp_for_data): Add case for NE_EXPR. + (build_outer_var_ref): Check for GF_OMP_FOR_KIND_SIMD bitwise. + (check_omp_nesting_restrictions): Same. + (lower_rec_input_clauses): Same. + (expand_omp_for): Same. + (lower_omp_for): Same. + (diagnose_sb_0): Adjust for Cilk Plus for loops. + (gate_expand_omp): Check for Cilk Plus. + (execute_lower_omp): Same. + (gate_diagnose_omp_blocks): Same. + * tree.h (OMP_LOOP_CHECK): New. + Adapt all OMP_FOR_* macros to use OMP_LOOP_CHECK. + * tree.def (CILK_SIMD): New entry. + * tree-pretty-print.c (dump_generic_node): Add case for CILK_SIMD. + * gimple-pretty-print.c (dump_gimple_omp_for): Add case for + GF_OMP_FOR_KIND_CILKSIMD. + * gimplify.c (gimplify_omp_for): Add case for CILK_SIMD. + (gimplify_expr): Same. + (is_gimple_stmt): Same. + +c-family/ + * c-cilkplus.c: New. + * c-pragma.c (init_pragma): Register "simd" pragma. + * c-pragma.h (enum pragma_kind): Add PRAGMA_CILK_SIMD enum. + (enum pragma_cilk_clause): New. + * c.opt (fcilkplus): New flag. + * c-common.h (c_finish_cilk_simd_loop): Protoize. + (c_finish_cilk_clauses): Same. + +c/ + * c-parser.c (c_parser_pragma): Add case for PRAGMA_CILK_SIMD. + (c_parser_cilk_verify_simd): New. + (c_parser_cilk_clause_vectorlength): New. + (c_parser_cilk_clause_linear): New. + (c_parser_cilk_clause_name): New. + (c_parser_cilk_all_clauses): New. + (c_parser_cilk_for_statement): New. + (c_parser_cilk_simd_construct): New. + * c-typeck.c (c_finish_bc_stmt): Add case for _Cilk_for loops. + +testsuite/ + * gcc.dg/cilk-plus: New directory and associated infrastructure. diff --git a/gcc/Makefile.in b/gcc/Makefile.in index b264f1bf363..e88672ce9e8 100644 --- a/gcc/Makefile.in +++ b/gcc/Makefile.in @@ -1150,7 +1150,7 @@ C_COMMON_OBJS = c-family/c-common.o c-family/c-cppbuiltin.o c-family/c-dump.o \ c-family/c-omp.o c-family/c-opts.o c-family/c-pch.o \ c-family/c-ppoutput.o c-family/c-pragma.o c-family/c-pretty-print.o \ c-family/c-semantics.o c-family/c-ada-spec.o tree-mudflap.o \ - c-family/array-notation-common.o + c-family/array-notation-common.o c-family/c-cilkplus.o # Language-independent object files. # We put the insn-*.o files first so that a parallel make will build @@ -1979,6 +1979,9 @@ c-family/c-lex.o : c-family/c-lex.c $(CONFIG_H) $(SYSTEM_H) coretypes.h \ c-family/c-omp.o : c-family/c-omp.c $(CONFIG_H) $(SYSTEM_H) coretypes.h \ $(TREE_H) $(C_COMMON_H) $(GIMPLE_H) langhooks.h +c-family/c-cilkplus.o : c-family/c-cilkplus.c $(CONFIG_H) $(SYSTEM_H) \ + coretypes.h $(TREE_H) $(C_COMMON_H) langhooks.h + CFLAGS-c-family/c-opts.o += @TARGET_SYSTEM_ROOT_DEFINE@ c-family/c-opts.o : c-family/c-opts.c $(CONFIG_H) $(SYSTEM_H) coretypes.h \ $(TREE_H) $(C_PRAGMA_H) $(FLAGS_H) toplev.h langhooks.h \ diff --git a/gcc/c-family/c-cilkplus.c b/gcc/c-family/c-cilkplus.c new file mode 100644 index 00000000000..111321bc9f2 --- /dev/null +++ b/gcc/c-family/c-cilkplus.c @@ -0,0 +1,406 @@ +/* This file contains routines to construct and validate Cilk Plus + constructs within the C and C++ front ends. + + Copyright (C) 2011-2013 Free Software Foundation, Inc. + Contributed by Balaji V. Iyer <balaji.v.iyer@intel.com>, + Aldy Hernandez <aldyh@redhat.com>. + +This file is part of GCC. + +GCC is free software; you can redistribute it and/or modify it +under the terms of the GNU General Public License as published by +the Free Software Foundation; either version 3, or (at your option) +any later version. + +GCC is distributed in the hope that it will be useful, but +WITHOUT ANY WARRANTY; without even the implied warranty of +MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU +General Public License for more details. + +You should have received a copy of the GNU General Public License +along with GCC; see the file COPYING3. If not see +<http://www.gnu.org/licenses/>. */ + +#include "config.h" +#include "system.h" +#include "coretypes.h" +#include "tree.h" +#include "c-common.h" + +/* Helper function for c_check_cilk_loop. + + Validate the increment in a _Cilk_for construct or a <#pragma simd> + for loop. + + LOC is the location of the `for' keyword. DECL is the induction + variable. INCR is the original increment expression. + + Returns the canonicalized increment expression for an OMP_FOR_INCR. + If there is a validation error, returns error_mark_node. */ + +static tree +c_check_cilk_loop_incr (location_t loc, tree decl, tree incr) +{ + if (EXPR_HAS_LOCATION (incr)) + loc = EXPR_LOCATION (incr); + + if (!incr) + { + error_at (loc, "missing increment"); + return error_mark_node; + } + + switch (TREE_CODE (incr)) + { + case POSTINCREMENT_EXPR: + case PREINCREMENT_EXPR: + case POSTDECREMENT_EXPR: + case PREDECREMENT_EXPR: + if (TREE_OPERAND (incr, 0) != decl) + break; + + // Bah... canonicalize into whatever OMP_FOR_INCR needs. + if (POINTER_TYPE_P (TREE_TYPE (decl)) + && TREE_OPERAND (incr, 1)) + { + tree t = fold_convert_loc (loc, + sizetype, TREE_OPERAND (incr, 1)); + + if (TREE_CODE (incr) == POSTDECREMENT_EXPR + || TREE_CODE (incr) == PREDECREMENT_EXPR) + t = fold_build1_loc (loc, NEGATE_EXPR, sizetype, t); + t = fold_build_pointer_plus (decl, t); + incr = build2 (MODIFY_EXPR, void_type_node, decl, t); + } + return incr; + + case MODIFY_EXPR: + { + tree rhs; + + if (TREE_OPERAND (incr, 0) != decl) + break; + + rhs = TREE_OPERAND (incr, 1); + if (TREE_CODE (rhs) == PLUS_EXPR + && (TREE_OPERAND (rhs, 0) == decl + || TREE_OPERAND (rhs, 1) == decl) + && INTEGRAL_TYPE_P (TREE_TYPE (rhs))) + return incr; + else if (TREE_CODE (rhs) == MINUS_EXPR + && TREE_OPERAND (rhs, 0) == decl + && INTEGRAL_TYPE_P (TREE_TYPE (rhs))) + return incr; + // Otherwise fail because only PLUS_EXPR and MINUS_EXPR are + // allowed. + break; + } + + default: + break; + } + + error_at (loc, "invalid increment expression"); + return error_mark_node; +} + +/* Callback for walk_tree to validate the body of a pragma simd loop + or _cilk_for loop. + + This function is passed in as a function pointer to walk_tree. *TP is + the current tree pointer, *WALK_SUBTREES is set to 0 by this function if + recursing into TP's subtrees is unnecessary. *DATA is a bool variable that + is set to false if an error has occured. */ + +tree +c_validate_cilk_plus_loop (tree *tp, int *walk_subtrees, void *data) +{ + if (!tp || !*tp) + return NULL_TREE; + + bool *valid = (bool *) data; + + switch (TREE_CODE (*tp)) + { + case CALL_EXPR: + { + tree fndecl = CALL_EXPR_FN (*tp); + + if (TREE_CODE (fndecl) == ADDR_EXPR) + fndecl = TREE_OPERAND (fndecl, 0); + if (TREE_CODE (fndecl) == FUNCTION_DECL) + { + if (setjmp_call_p (fndecl)) + { + error_at (EXPR_LOCATION (*tp), + "calls to setjmp are not allowed within loops " + "annotated with #pragma simd"); + *valid = false; + *walk_subtrees = 0; + } + } + break; + } + + case OMP_PARALLEL: + case OMP_TASK: + case OMP_FOR: + case OMP_SIMD: + case OMP_SECTIONS: + case OMP_SINGLE: + case OMP_SECTION: + case OMP_MASTER: + case OMP_ORDERED: + case OMP_CRITICAL: + case OMP_ATOMIC: + case OMP_ATOMIC_READ: + case OMP_ATOMIC_CAPTURE_OLD: + case OMP_ATOMIC_CAPTURE_NEW: + error_at (EXPR_LOCATION (*tp), "OpenMP statements are not allowed " + "within loops annotated with #pragma simd"); + *valid = false; + *walk_subtrees = 0; + break; + + default: + break; + } + return NULL_TREE; +} + +/* Validate the body of a _Cilk_for construct or a <#pragma simd> for + loop. + + Returns true if there were no errors, false otherwise. */ + +static bool +c_check_cilk_loop_body (tree body) +{ + bool valid = true; + walk_tree (&body, c_validate_cilk_plus_loop, (void *) &valid, NULL); + return valid; +} + +/* Validate a _Cilk_for construct (or a #pragma simd for loop, which + has the same syntactic restrictions). Returns TRUE if there were + no errors, FALSE otherwise. LOC is the location of the for. DECL + is the controlling variable. COND is the condition. INCRP is a + pointer the increment expression (in case, the increment needs to + be canonicalized). BODY is the body of the LOOP. */ + +static bool +c_check_cilk_loop (location_t loc, tree decl, tree cond, tree *incrp, + tree body) +{ + tree incr = *incrp; + + if (decl == error_mark_node + || cond == error_mark_node + || incr == error_mark_node + || body == error_mark_node) + return false; + + /* Validate the initialization. */ + gcc_assert (decl != NULL); + if (TREE_THIS_VOLATILE (decl)) + { + error_at (loc, "induction variable cannot be volatile"); + return false; + } + if (DECL_EXTERNAL (decl)) + { + error_at (loc, "induction variable cannot be extern"); + return false; + } + if (TREE_STATIC (decl)) + { + error_at (loc, "induction variable cannot be static"); + return false; + } + if (DECL_REGISTER (decl)) + { + error_at (loc, "induction variable cannot be declared register"); + return false; + } + if (!INTEGRAL_TYPE_P (TREE_TYPE (decl)) + && !POINTER_TYPE_P (TREE_TYPE (decl))) + { + error_at (loc, "initialization variable must be of integral " + "or pointer type"); + return false; + } + + /* Validate the condition. */ + if (!cond) + { + error_at (loc, "missing condition"); + return false; + } + bool cond_ok = false; + if (TREE_CODE (cond) == NE_EXPR + || TREE_CODE (cond) == LT_EXPR + || TREE_CODE (cond) == LE_EXPR + || TREE_CODE (cond) == GT_EXPR + || TREE_CODE (cond) == GE_EXPR) + { + /* Comparison must either be: + DECL <comparison_operator> EXPR + EXPR <comparison_operator> DECL + */ + if (decl == TREE_OPERAND (cond, 0)) + cond_ok = true; + else if (decl == TREE_OPERAND (cond, 1)) + { + /* Canonicalize the comparison so the DECL is on the LHS. */ + TREE_SET_CODE (cond, + swap_tree_comparison (TREE_CODE (cond))); + TREE_OPERAND (cond, 1) = TREE_OPERAND (cond, 0); + TREE_OPERAND (cond, 0) = decl; + cond_ok = true; + } + } + if (!cond_ok) + { + error_at (loc, "invalid controlling predicate"); + return false; + } + + /* Validate and canonicalize the increment. */ + incr = c_check_cilk_loop_incr (loc, decl, incr); + if (incr == error_mark_node) + return false; + *incrp = incr; + + if (!c_check_cilk_loop_body (body)) + return false; + + return true; +} + +/* Adjust any clauses to match the requirements for OpenMP. */ + +static tree +adjust_clauses_for_omp (tree clauses) +{ + return clauses; +} + +/* Validate and emit code for the FOR loop following a #<pragma simd> + construct. + + LOC is the location of the location of the FOR. + DECL is the iteration variable. + INIT is the initialization expression. + COND is the controlling predicate. + INCR is the increment expression. + BODY is the body of the loop. + CLAUSES are the clauses associated with the pragma simd loop. + + Returns the generated statement. */ + +tree +c_finish_cilk_simd_loop (location_t loc, + tree decl, + tree init, tree cond, tree incr, + tree body, + tree clauses) +{ + location_t rhs_loc; + + if (!c_check_cilk_loop (loc, decl, cond, &incr, body)) + return NULL; + + /* In the case of "for (int i = 0...)", init will be a decl. It should + have a DECL_INITIAL that we can turn into an assignment. */ + if (init == decl) + { + rhs_loc = DECL_SOURCE_LOCATION (decl); + + init = DECL_INITIAL (decl); + if (init == NULL) + { + error_at (rhs_loc, "%qE is not initialized", decl); + init = integer_zero_node; + return NULL; + } + + init = build_modify_expr (loc, decl, NULL_TREE, NOP_EXPR, rhs_loc, + init, NULL_TREE); + } + + // The C++ parser just gives us the rhs. + if (TREE_CODE (init) != MODIFY_EXPR) + init = build2 (MODIFY_EXPR, void_type_node, decl, init); + + gcc_assert (TREE_OPERAND (init, 0) == decl); + + tree initv = make_tree_vec (1); + tree condv = make_tree_vec (1); + tree incrv = make_tree_vec (1); + TREE_VEC_ELT (initv, 0) = init; + TREE_VEC_ELT (condv, 0) = cond; + TREE_VEC_ELT (incrv, 0) = incr; + + tree t = make_node (CILK_SIMD); + TREE_TYPE (t) = void_type_node; + OMP_FOR_INIT (t) = initv; + OMP_FOR_COND (t) = condv; + OMP_FOR_INCR (t) = incrv; + OMP_FOR_BODY (t) = body; + OMP_FOR_PRE_BODY (t) = NULL; + OMP_FOR_CLAUSES (t) = adjust_clauses_for_omp (clauses); + + SET_EXPR_LOCATION (t, loc); + return add_stmt (t); +} + +/* Validate and emit code for <#pragma simd> clauses. */ + +tree +c_finish_cilk_clauses (tree clauses) +{ + for (tree c = clauses; c; c = OMP_CLAUSE_CHAIN (c)) + { + tree prev = clauses; + + /* If a variable appears in a linear clause it cannot appear in + any other OMP clause. */ + if (OMP_CLAUSE_CODE (c) == OMP_CLAUSE_LINEAR) + for (tree c2 = clauses; c2; c2 = OMP_CLAUSE_CHAIN (c2)) + { + if (c == c2) + continue; + enum omp_clause_code code = OMP_CLAUSE_CODE (c2); + + switch (code) + { + case OMP_CLAUSE_LINEAR: + case OMP_CLAUSE_PRIVATE: + case OMP_CLAUSE_FIRSTPRIVATE: + case OMP_CLAUSE_LASTPRIVATE: + case OMP_CLAUSE_REDUCTION: + break; + + case OMP_CLAUSE_SAFELEN: + goto next; + + default: + gcc_unreachable (); + } + + if (OMP_CLAUSE_DECL (c) == OMP_CLAUSE_DECL (c2)) + { + error_at (OMP_CLAUSE_LOCATION (c2), + "variable appears in more than one clause"); + inform (OMP_CLAUSE_LOCATION (c), + "multiple clause defined here"); + // Remove problematic clauses. + OMP_CLAUSE_CHAIN (prev) = OMP_CLAUSE_CHAIN (c2); + } + next: + prev = c2; + } + } + + return clauses; +} diff --git a/gcc/c-family/c-common.h b/gcc/c-family/c-common.h index 6dfcffd7921..2cf1e14dec7 100644 --- a/gcc/c-family/c-common.h +++ b/gcc/c-family/c-common.h @@ -521,6 +521,11 @@ struct GTY(()) c_language_function { #define building_stmt_list_p() (stmt_list_stack && !stmt_list_stack->is_empty()) +/* In c-cilkplus.c */ +extern tree c_finish_cilk_simd_loop (location_t, tree, tree, tree, tree, + tree, tree); +extern tree c_finish_cilk_clauses (tree); + /* Language-specific hooks. */ /* If non-NULL, this function is called after a precompile header file @@ -1136,6 +1141,12 @@ enum stv_conv { extern enum stv_conv scalar_to_vector (location_t loc, enum tree_code code, tree op0, tree op1, bool); +/* In c-cilkplus.c */ +extern tree c_finish_cilk_simd_loop (location_t, tree, tree, tree, tree, + tree, tree); +extern tree c_finish_cilk_clauses (tree); +extern tree c_validate_cilk_plus_loop (tree *, int *, void *); + /* These #defines allow users to access different operands of the array notation tree. */ diff --git a/gcc/c-family/c-pragma.c b/gcc/c-family/c-pragma.c index 309859fc8ec..428ecfa4c12 100644 --- a/gcc/c-family/c-pragma.c +++ b/gcc/c-family/c-pragma.c @@ -1349,6 +1349,12 @@ init_pragma (void) omp_pragmas[i].id, true, true); } + if (flag_enable_cilkplus && !flag_preprocess_only) + { + cpp_register_deferred_pragma (parse_in, NULL, "simd", + PRAGMA_CILK_SIMD, true, false); + } + if (!flag_preprocess_only) cpp_register_deferred_pragma (parse_in, "GCC", "pch_preprocess", PRAGMA_GCC_PCH_PREPROCESS, false, false); diff --git a/gcc/c-family/c-pragma.h b/gcc/c-family/c-pragma.h index 41215db00a0..4c88dc3f58e 100644 --- a/gcc/c-family/c-pragma.h +++ b/gcc/c-family/c-pragma.h @@ -45,6 +45,9 @@ typedef enum pragma_kind { PRAGMA_OMP_TASKYIELD, PRAGMA_OMP_THREADPRIVATE, + /* Top level clause to handle all Cilk Plus pragma simd clauses. */ + PRAGMA_CILK_SIMD, + PRAGMA_GCC_PCH_PREPROCESS, PRAGMA_FIRST_EXTERNAL @@ -75,6 +78,17 @@ typedef enum pragma_omp_clause { PRAGMA_OMP_CLAUSE_MERGEABLE } pragma_omp_clause; +/* All Cilk Plus #pragma omp clauses. */ +typedef enum pragma_cilk_clause { + PRAGMA_CILK_CLAUSE_NONE = 0, + PRAGMA_CILK_CLAUSE_VECTORLENGTH, + PRAGMA_CILK_CLAUSE_LINEAR, + PRAGMA_CILK_CLAUSE_PRIVATE, + PRAGMA_CILK_CLAUSE_FIRSTPRIVATE, + PRAGMA_CILK_CLAUSE_LASTPRIVATE, + PRAGMA_CILK_CLAUSE_REDUCTION +} pragma_cilk_clause; + extern struct cpp_reader* parse_in; /* It's safe to always leave visibility pragma enabled as if diff --git a/gcc/c/c-parser.c b/gcc/c/c-parser.c index c7846cedccb..b5c09f9601f 100644 --- a/gcc/c/c-parser.c +++ b/gcc/c/c-parser.c @@ -1216,6 +1216,10 @@ static void c_parser_objc_at_dynamic_declaration (c_parser *); static bool c_parser_objc_diagnose_bad_element_prefix (c_parser *, struct c_declspecs *); +/* Cilk Plus supporting routines. */ +static void c_parser_cilk_for_statement (c_parser *, enum rid, tree); +static void c_parser_cilk_simd_construct (c_parser *); +static bool c_parser_cilk_verify_simd (c_parser *, enum pragma_context); static tree c_parser_array_notation (location_t, c_parser *, tree, tree); /* Parse a translation unit (C90 6.7, C99 6.9). @@ -8729,6 +8733,13 @@ c_parser_pragma (c_parser *parser, enum pragma_context context) c_parser_skip_until_found (parser, CPP_PRAGMA_EOL, NULL); return false; + case PRAGMA_CILK_SIMD: + if (!c_parser_cilk_verify_simd (parser, context)) + return false; + c_parser_consume_pragma (parser); + c_parser_cilk_simd_construct (parser); + return false; + default: if (id < PRAGMA_FIRST_EXTERNAL) { @@ -10761,7 +10772,391 @@ c_parser_omp_threadprivate (c_parser *parser) c_parser_skip_to_pragma_eol (parser); } + +/* Cilk Plus <#pragma simd> parsing routines. */ + +/* Helper function for c_parser_pragma. Perform some sanity checking + for <#pragma simd> constructs. Returns FALSE if there was a + problem. */ + +static bool +c_parser_cilk_verify_simd (c_parser *parser, + enum pragma_context context) +{ + if (!flag_enable_cilkplus) + { + warning (0, "pragma simd ignored because -fcilkplus is not enabled"); + c_parser_skip_until_found (parser, CPP_PRAGMA_EOL, NULL); + return false; + } + if (!flag_tree_vectorize) + { + warning (0, "pragma simd is useless without -ftree-vectorize"); + c_parser_skip_until_found (parser, CPP_PRAGMA_EOL, NULL); + return false; + } + if (context == pragma_external) + { + c_parser_error (parser,"pragma simd must be inside a function"); + c_parser_skip_until_found (parser, CPP_PRAGMA_EOL, NULL); + return false; + } + return true; +} + +/* Cilk Plus: + vectorlength ( constant-expression ) */ + +static tree +c_parser_cilk_clause_vectorlength (c_parser *parser, tree clauses) +{ + /* The vectorlength clause behaves exactly like OpenMP's safelen + clause. Represent it in OpenMP terms. */ + check_no_duplicate_clause (clauses, OMP_CLAUSE_SAFELEN, "vectorlength"); + + if (!c_parser_require (parser, CPP_OPEN_PAREN, "expected %<(%>")) + return clauses; + + location_t loc = c_parser_peek_token (parser)->location; + tree expr = c_parser_expr_no_commas (parser, NULL).value; + expr = c_fully_fold (expr, false, NULL); + + if (!TREE_TYPE (expr) + || !TREE_CONSTANT (expr) + || !INTEGRAL_TYPE_P (TREE_TYPE (expr))) + error_at (loc, "vectorlength must be an integer constant"); + else if (exact_log2 (TREE_INT_CST_LOW (expr)) == -1) + error_at (loc, "vectorlength must be a power of 2"); + else + { + tree u = build_omp_clause (loc, OMP_CLAUSE_SAFELEN); + OMP_CLAUSE_SAFELEN_EXPR (u) = expr; + OMP_CLAUSE_CHAIN (u) = clauses; + clauses = u; + } + + c_parser_require (parser, CPP_CLOSE_PAREN, "expected %<)%>"); + + return clauses; +} + +/* Cilk Plus: + linear ( simd-linear-variable-list ) + + simd-linear-variable-list: + simd-linear-variable + simd-linear-variable-list , simd-linear-variable + + simd-linear-variable: + id-expression + id-expression : simd-linear-step + + simd-linear-step: + conditional-expression */ + +static tree +c_parser_cilk_clause_linear (c_parser *parser, tree clauses) +{ + if (!c_parser_require (parser, CPP_OPEN_PAREN, "expected %<(%>")) + return clauses; + + location_t loc = c_parser_peek_token (parser)->location; + + if (c_parser_next_token_is_not (parser, CPP_NAME) + || c_parser_peek_token (parser)->id_kind != C_ID_ID) + c_parser_error (parser, "expected identifier"); + + while (c_parser_next_token_is (parser, CPP_NAME) + && c_parser_peek_token (parser)->id_kind == C_ID_ID) + { + tree var = lookup_name (c_parser_peek_token (parser)->value); + + if (var == NULL) + { + undeclared_variable (c_parser_peek_token (parser)->location, + c_parser_peek_token (parser)->value); + c_parser_consume_token (parser); + } + else if (var == error_mark_node) + c_parser_consume_token (parser); + else + { + tree step = integer_one_node; + + /* Parse the linear step if present. */ + if (c_parser_peek_2nd_token (parser)->type == CPP_COLON) + { + c_parser_consume_token (parser); + c_parser_consume_token (parser); + + tree expr = c_parser_expr_no_commas (parser, NULL).value; + expr = c_fully_fold (expr, false, NULL); + + if (!TREE_TYPE (expr) + || !TREE_CONSTANT (expr) + || !INTEGRAL_TYPE_P (TREE_TYPE (expr))) + c_parser_error (parser, + "step size must be an integer constant"); + else + step = expr; + } + else + c_parser_consume_token (parser); + + /* Use OMP_CLAUSE_LINEAR, which has the same semantics. */ + tree u = build_omp_clause (loc, OMP_CLAUSE_LINEAR); + OMP_CLAUSE_DECL (u) = var; + OMP_CLAUSE_LINEAR_STEP (u) = step; + OMP_CLAUSE_CHAIN (u) = clauses; + clauses = u; + } + + if (c_parser_next_token_is_not (parser, CPP_COMMA)) + break; + + c_parser_consume_token (parser); + } + + c_parser_skip_until_found (parser, CPP_CLOSE_PAREN, "expected %<)%>"); + + return clauses; +} + +/* Returns the name of the next clause. If the clause is not + recognized SIMD_OMP_CLAUSE_NONE is returned and the next token is + not consumed. Otherwise, the appropriate pragma_simd_clause is + returned and the token is consumed. */ + +static pragma_cilk_clause +c_parser_cilk_clause_name (c_parser *parser) +{ + pragma_cilk_clause result; + c_token *token = c_parser_peek_token (parser); + + if (!token->value || token->type != CPP_NAME) + return PRAGMA_CILK_CLAUSE_NONE; + + const char *p = IDENTIFIER_POINTER (token->value); + + if (!strcmp (p, "vectorlength")) + result = PRAGMA_CILK_CLAUSE_VECTORLENGTH; + else if (!strcmp (p, "linear")) + result = PRAGMA_CILK_CLAUSE_LINEAR; + else if (!strcmp (p, "private")) + result = PRAGMA_CILK_CLAUSE_PRIVATE; + else if (!strcmp (p, "firstprivate")) + result = PRAGMA_CILK_CLAUSE_FIRSTPRIVATE; + else if (!strcmp (p, "lastprivate")) + result = PRAGMA_CILK_CLAUSE_LASTPRIVATE; + else if (!strcmp (p, "reduction")) + result = PRAGMA_CILK_CLAUSE_REDUCTION; + else + return PRAGMA_CILK_CLAUSE_NONE; + + c_parser_consume_token (parser); + return result; +} +/* Parse all #<pragma simd> clauses. Return the list of clauses + found. */ + +static tree +c_parser_cilk_all_clauses (c_parser *parser) +{ + tree clauses = NULL; + + while (c_parser_next_token_is_not (parser, CPP_PRAGMA_EOL)) + { + pragma_cilk_clause c_kind; + + c_kind = c_parser_cilk_clause_name (parser); + + switch (c_kind) + { + case PRAGMA_CILK_CLAUSE_VECTORLENGTH: + clauses = c_parser_cilk_clause_vectorlength (parser, clauses); + break; + case PRAGMA_CILK_CLAUSE_LINEAR: + clauses = c_parser_cilk_clause_linear (parser, clauses); + break; + case PRAGMA_CILK_CLAUSE_PRIVATE: + /* Use the OpenMP counterpart. */ + clauses = c_parser_omp_clause_private (parser, clauses); + break; + case PRAGMA_CILK_CLAUSE_FIRSTPRIVATE: + /* Use the OpenMP counterpart. */ + clauses = c_parser_omp_clause_firstprivate (parser, clauses); + break; + case PRAGMA_CILK_CLAUSE_LASTPRIVATE: + /* Use the OpenMP counterpart. */ + clauses = c_parser_omp_clause_lastprivate (parser, clauses); + break; + case PRAGMA_CILK_CLAUSE_REDUCTION: + /* Use the OpenMP counterpart. */ + clauses = c_parser_omp_clause_reduction (parser, clauses); + break; + default: + c_parser_error (parser, "expected %<#pragma simd%> clause"); + goto saw_error; + } + } + + saw_error: + c_parser_skip_to_pragma_eol (parser); + return c_finish_cilk_clauses (clauses); +} + +/* Parse the restriction form of the for statement allowed by + Cilk Plus. This function parses both the _CILK_FOR construct as + well as the for loop following a <#pragma simd> construct, both of + which have the same syntactic restrictions. + + FOR_KEYWORD can be either RID_CILK_FOR or RID_FOR, for parsing + _Cilk_for or the <#pragma simd> for loop construct respectively. + + (NOTE: For now, only RID_FOR is handled). + + For a <#pragma simd>, CLAUSES are the clauses that should have been + previously parsed. If there are none, or if we are parsing a + _Cilk_for instead, this will be NULL. */ + +static void +c_parser_cilk_for_statement (c_parser *parser, enum rid for_keyword, + tree clauses) +{ + tree init, decl, cond, stmt; + tree block, incr, save_break, save_cont, body; + location_t loc; + bool fail = false; + + gcc_assert (/*for_keyword == RID_CILK_FOR || */for_keyword == RID_FOR); + + if (!c_parser_next_token_is_keyword (parser, for_keyword)) + { + if (for_keyword == RID_FOR) + c_parser_error (parser, "for statement expected"); + else + c_parser_error (parser, "_Cilk_for statement expected"); + return; + } + + loc = c_parser_peek_token (parser)->location; + c_parser_consume_token (parser); + + block = c_begin_compound_stmt (true); + + if (!c_parser_require (parser, CPP_OPEN_PAREN, "expected %<(%>")) + { + add_stmt (c_end_compound_stmt (loc, block, true)); + return; + } + + /* Parse the initialization declaration. */ + if (c_parser_next_tokens_start_declaration (parser)) + { + c_parser_declaration_or_fndef (parser, true, false, false, + false, false, NULL); + decl = check_for_loop_decls (loc, flag_isoc99); + if (decl == NULL) + goto error_init; + if (DECL_INITIAL (decl) == error_mark_node) + decl = error_mark_node; + init = decl; + } + else if (c_parser_next_token_is (parser, CPP_NAME) + && c_parser_peek_2nd_token (parser)->type == CPP_EQ) + { + struct c_expr decl_exp; + struct c_expr init_exp; + location_t init_loc; + + decl_exp = c_parser_postfix_expression (parser); + decl = decl_exp.value; + + c_parser_require (parser, CPP_EQ, "expected %<=%>"); + + init_loc = c_parser_peek_token (parser)->location; + init_exp = c_parser_expr_no_commas (parser, NULL); + init_exp = default_function_array_read_conversion (init_loc, + init_exp); + init = build_modify_expr (init_loc, decl, decl_exp.original_type, + NOP_EXPR, init_loc, init_exp.value, + init_exp.original_type); + init = c_process_expr_stmt (init_loc, init); + + c_parser_skip_until_found (parser, CPP_SEMICOLON, "expected %<;%>"); + } + else + { + error_init: + c_parser_error (parser, + "expected iteration declaration or initialization"); + c_parser_skip_until_found (parser, CPP_CLOSE_PAREN, + "expected %<)%>"); + return; + } + + /* Parse the loop condition. */ + cond = NULL_TREE; + if (c_parser_next_token_is_not (parser, CPP_SEMICOLON)) + { + location_t cond_loc = c_parser_peek_token (parser)->location; + struct c_expr cond_expr = c_parser_binary_expression (parser, NULL, + PREC_NONE); + + cond = cond_expr.value; + cond = c_objc_common_truthvalue_conversion (cond_loc, cond); + cond = c_fully_fold (cond, false, NULL); + } + c_parser_skip_until_found (parser, CPP_SEMICOLON, "expected %<;%>"); + + /* Parse the increment expression. */ + incr = NULL_TREE; + if (c_parser_next_token_is_not (parser, CPP_CLOSE_PAREN)) + { + location_t incr_loc = c_parser_peek_token (parser)->location; + incr = c_process_expr_stmt (incr_loc, + c_parser_expression (parser).value); + } + c_parser_skip_until_found (parser, CPP_CLOSE_PAREN, "expected %<)%>"); + + if (decl == NULL || decl == error_mark_node || init == error_mark_node) + fail = true; + + save_break = c_break_label; + /* Magic number to inform c_finish_bc_stmt() that we are within a + Cilk for construct. */ + c_break_label = build_int_cst (size_type_node, 2); + + save_cont = c_cont_label; + c_cont_label = NULL_TREE; + body = c_parser_c99_block_statement (parser); + c_break_label = save_break; + c_cont_label = save_cont; + + if (!fail) + { + if (for_keyword == RID_FOR) + c_finish_cilk_simd_loop (loc, decl, init, cond, incr, body, clauses); + } + + stmt = c_end_compound_stmt (loc, block, true); + add_stmt (stmt); + c_break_label = save_break; + c_cont_label = save_cont; +} + +/* Main entry point for parsing Cilk Plus <#pragma simd> for + loops. */ + +static void +c_parser_cilk_simd_construct (c_parser *parser) +{ + tree clauses = c_parser_cilk_all_clauses (parser); + + c_parser_cilk_for_statement (parser, RID_FOR, clauses); +} + /* Parse a transaction attribute (GCC Extension). transaction-attribute: diff --git a/gcc/c/c-typeck.c b/gcc/c/c-typeck.c index 3a923111429..d5e41759976 100644 --- a/gcc/c/c-typeck.c +++ b/gcc/c/c-typeck.c @@ -9153,6 +9153,13 @@ c_finish_bc_stmt (location_t loc, tree *label_p, bool is_break) error_at (loc, "break statement used with OpenMP for loop"); return NULL_TREE; + case 2: + if (is_break) + error ("break statement within <#pragma simd> loop body"); + else + error ("continue statement within <#pragma simd> loop loop"); + return NULL_TREE; + default: gcc_unreachable (); } diff --git a/gcc/cp/ChangeLog.cilkplus b/gcc/cp/ChangeLog.cilkplus new file mode 100644 index 00000000000..f0ee3ee6ed8 --- /dev/null +++ b/gcc/cp/ChangeLog.cilkplus @@ -0,0 +1,28 @@ +2013-06-26 Aldy Hernandez <aldyh@redhat.com> + + * cp-gimplify.c (cp_gimplify_expr): Add case for CILK_SIMD. + (cp_genericize_r): Same. + * pt.c (tsubst_expr): Same. + * semantics.c (finish_omp_for): Same. + +2013-05-21 Balaji V. Iyer <balaji.v.iyer@intel.com> + Aldy Hernandez <aldyh@redhat.com> + + * cp-tree.h (p_simd_valid_stmts_in_body_p): New prototype. + (finish_cilk_for_cond): Likewise. + * parser.h (IN_CILK_P_SIMD_FOR): New #define. + * Make-lang.in (CXX_AND_OBJCXX_OBJS): Added new obj-file cp-cilkplus.o + * cp-cilkplus.c: New file. + * semantics.c (finish_cilk_for_cond): New. + * parser.c (cp_parser_pragma): Added a PRAGMA_CILK_SIMD case. + (cp_parser_cilk_simd_vectorlength): New function. + (cp_parser_cilk_simd_linear): Likewise. + (cp_parser_cilk_simd_clause_name): Likewise. + (cp_parser_cilk_simd_all_clauses): Likewise. + (cp_parser_cilk_simd_construct): Likewise. + (cp_parser_simd_for_init_statement): Likewise. + (cp_parser_cilk_for_expression_iterator): Likewise. + (cp_parser_cilk_for_condition): Likewise. + (cp_parser_cilk_for): Likewise. + (cp_parser_jump_statement): Added a IN_CILK_P_SIMD_FOR case. + diff --git a/gcc/cp/Make-lang.in b/gcc/cp/Make-lang.in index 6e80bcf8c10..fa36369578d 100644 --- a/gcc/cp/Make-lang.in +++ b/gcc/cp/Make-lang.in @@ -80,6 +80,7 @@ CXX_AND_OBJCXX_OBJS = cp/call.o cp/decl.o cp/expr.o cp/pt.o cp/typeck2.o \ cp/typeck.o cp/cvt.o cp/except.o cp/friend.o cp/init.o cp/method.o \ cp/search.o cp/semantics.o cp/tree.o cp/repo.o cp/dump.o cp/optimize.o \ cp/mangle.o cp/cp-objcp-common.o cp/name-lookup.o cp/cxx-pretty-print.o \ + cp/cp-cilkplus.o \ cp/cp-gimplify.o cp/cp-array-notation.o $(CXX_C_OBJS) # Language-specific object files for C++. @@ -348,3 +349,5 @@ cp/name-lookup.o: cp/name-lookup.c $(CONFIG_H) $(SYSTEM_H) coretypes.h \ cp/cxx-pretty-print.o: cp/cxx-pretty-print.c $(CXX_PRETTY_PRINT_H) \ $(CONFIG_H) $(SYSTEM_H) $(TM_H) coretypes.h $(CXX_TREE_H) tree-pretty-print.h +cp/cp-cilkplus.o: cp/cp-cilkplus.c $(CONFIG_H) $(SYSTEM_H) coretypes.h \ + $(CXX_TREE_H) $(DIAGNOSTIC_CORE_H) diff --git a/gcc/cp/cp-cilkplus.c b/gcc/cp/cp-cilkplus.c new file mode 100644 index 00000000000..aa803438e5d --- /dev/null +++ b/gcc/cp/cp-cilkplus.c @@ -0,0 +1,78 @@ +/* This file is part of the Intel(R) Cilk(TM) Plus support + This file contains routines to handle Cilk Plus specific + routines for the C++ Compiler. + Copyright (C) 2013 Free Software Foundation, Inc. + Contributed by Balaji V. Iyer <balaji.v.iyer@intel.com>, + Aldy Hernandez <aldyh@redhat.com>. + + This file is part of GCC. + + GCC is free software; you can redistribute it and/or modify it + under the terms of the GNU General Public License as published by + the Free Software Foundation; either version 3, or (at your option) + any later version. + + GCC is distributed in the hope that it will be useful, but + WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + General Public License for more details. + + You should have received a copy of the GNU General Public License + along with GCC; see the file COPYING3. If not see + <http://www.gnu.org/licenses/>. */ + +#include "config.h" +#include "system.h" +#include "coretypes.h" +#include "cp-tree.h" +#include "diagnostic-core.h" + + +/* Callback for cp_walk_tree to validate the body of a pragma simd loop + or _cilk_for loop. + + This function is passed in as a function pointer to walk_tree. *TP is + the current tree pointer, *WALK_SUBTREES is set to 0 by this function if + recursing into TP's subtrees is unnecessary. *DATA is a bool variable that + is set to false if an error has occured. */ + +static tree +cpp_validate_cilk_plus_loop_aux (tree *tp, int *walk_subtrees, void *data) +{ + bool *valid = (bool *) data; + location_t loc = EXPR_HAS_LOCATION (*tp) ? EXPR_LOCATION (*tp) : + UNKNOWN_LOCATION; + + if (!tp || !*tp) + return NULL_TREE; + + if (TREE_CODE (*tp) == THROW_EXPR) + { + error_at (loc, "throw expressions are not allowed inside loops " + "marked with pragma simd"); + *walk_subtrees = 0; + *valid = false; + } + else if (TREE_CODE (*tp) == TRY_BLOCK) + { + error_at (loc, "try statements are not allowed inside loops marked " + "with #pragma simd"); + *valid = false; + *walk_subtrees = 0; + } + return NULL_TREE; +} + + +/* Walks through all the subtrees of BODY using walk_tree to make sure + invalid statements/expressions are not found inside BODY. Returns + false if any invalid statements are found. */ + +bool +cpp_validate_cilk_plus_loop (tree body) +{ + bool valid = true; + cp_walk_tree (&body, cpp_validate_cilk_plus_loop_aux, + (void *) &valid, NULL); + return valid; +} diff --git a/gcc/cp/cp-tree.h b/gcc/cp/cp-tree.h index 01d906e9116..a5f84fd4708 100644 --- a/gcc/cp/cp-tree.h +++ b/gcc/cp/cp-tree.h @@ -6142,6 +6142,10 @@ extern bool cxx_omp_privatize_by_reference (const_tree); extern void suggest_alternatives_for (location_t, tree); extern tree strip_using_decl (tree); +/* In cp-cilkplus.c. */ +extern bool cpp_validate_cilk_plus_loop (tree); +extern tree finish_cilk_for_cond (tree); + /* In cp/cp-array-notations.c */ extern tree expand_array_notation_exprs (tree); bool cilkplus_an_triplet_types_ok_p (location_t, tree, tree, tree, diff --git a/gcc/cp/parser.c b/gcc/cp/parser.c index 6e8293b024e..b6c128941ad 100644 --- a/gcc/cp/parser.c +++ b/gcc/cp/parser.c @@ -231,6 +231,11 @@ static void cp_parser_initial_pragma static tree cp_literal_operator_id (const char *); +static void cp_parser_cilk_simd_construct + (cp_parser *, cp_token *); +static tree cp_parser_cilk_for + (cp_parser *, enum rid, tree); + /* Manifest constants. */ #define CP_LEXER_BUFFER_SIZE ((256 * 1024) / sizeof (cp_token)) #define CP_SAVED_TOKEN_STACK 5 @@ -10376,6 +10381,10 @@ cp_parser_jump_statement (cp_parser* parser) case IN_OMP_FOR: error_at (token->location, "break statement used with OpenMP for loop"); break; + case IN_CILK_P_SIMD_FOR: + error_at (token->location, + "break statement within <#pragma simd> loop body"); + break; } cp_parser_require (parser, CPP_SEMICOLON, RT_SEMICOLON); break; @@ -10393,6 +10402,10 @@ cp_parser_jump_statement (cp_parser* parser) case IN_OMP_BLOCK: error_at (token->location, "invalid exit from OpenMP structured block"); break; + case IN_CILK_P_SIMD_FOR: + error_at (token->location, + "continue statement within <#pragma simd> loop loop"); + break; default: gcc_unreachable (); } @@ -28732,6 +28745,16 @@ cp_parser_pragma (cp_parser *parser, enum pragma_context context) "%<#pragma omp sections%> construct"); break; + case PRAGMA_CILK_SIMD: + if (context == pragma_external) + { + error_at (pragma_tok->location, + "%<#pragma simd%> must be inside a function"); + break; + } + cp_parser_cilk_simd_construct (parser, pragma_tok); + return true; + default: gcc_assert (id >= PRAGMA_FIRST_EXTERNAL); c_invoke_pragma_handler (id); @@ -28797,4 +28820,522 @@ c_parse_file (void) the_parser = NULL; } + +/* Parses the Cilk Plus #pragma simd vectorlength clause: + Syntax: + vectorlength ( constant-expression ) */ + +static tree +cp_parser_cilk_simd_vectorlength (cp_parser *parser, tree clauses) +{ + location_t loc = cp_lexer_peek_token (parser->lexer)->location; + tree expr; + /* The vectorlength clause behaves exactly like OpenMP's safelen + clause. Thus, vectorlength is represented as OMP 4.0 + safelen. */ + check_no_duplicate_clause (clauses, OMP_CLAUSE_SAFELEN, "vectorlength", loc); + + if (!cp_parser_require (parser, CPP_OPEN_PAREN, RT_OPEN_PAREN)) + return error_mark_node; + + expr = cp_parser_constant_expression (parser, false, NULL); + expr = maybe_constant_value (expr); + + if (TREE_CONSTANT (expr) + && exact_log2 (TREE_INT_CST_LOW (expr)) == -1) + error_at (loc, "vectorlength must be a power of 2"); + else if (expr != error_mark_node) + { + tree c = build_omp_clause (loc, OMP_CLAUSE_SAFELEN); + OMP_CLAUSE_SAFELEN_EXPR (c) = expr; + OMP_CLAUSE_CHAIN (c) = clauses; + clauses = c; + } + + if (!cp_parser_require (parser, CPP_CLOSE_PAREN, RT_CLOSE_PAREN)) + return error_mark_node; + return clauses; +} + +/* Handles the Cilk Plus #pragma simd linear clause. + Syntax: + linear ( simd-linear-variable-list ) + + simd-linear-variable-list: + simd-linear-variable + simd-linear-variable-list , simd-linear-variable + + simd-linear-variable: + id-expression + id-expression : simd-linear-step + + simd-linear-step: + conditional-expression */ + +static tree +cp_parser_cilk_simd_linear (cp_parser *parser, tree clauses) +{ + location_t loc = cp_lexer_peek_token (parser->lexer)->location; + + if (!cp_parser_require (parser, CPP_OPEN_PAREN, RT_OPEN_PAREN)) + return clauses; + if (cp_lexer_next_token_is_not (parser->lexer, CPP_NAME)) + { + cp_parser_error (parser, "expected identifier"); + cp_parser_skip_to_closing_parenthesis (parser, false, false, true); + return error_mark_node; + } + + while (1) + { + cp_token *token = cp_lexer_peek_token (parser->lexer); + if (cp_lexer_next_token_is_not (parser->lexer, CPP_NAME)) + { + cp_parser_error (parser, "expected variable-name"); + clauses = error_mark_node; + break; + } + + tree var_name = cp_parser_id_expression (parser, false, true, NULL, + false, false); + tree decl = cp_parser_lookup_name_simple (parser, var_name, + token->location); + if (decl == error_mark_node) + { + cp_parser_name_lookup_error (parser, var_name, decl, NLE_NULL, + token->location); + clauses = error_mark_node; + } + else + { + tree e = NULL_TREE; + tree step_size = integer_one_node; + + /* If present, parse the linear step. Otherwise, assume the default + value of 1. */ + if (cp_lexer_peek_token (parser->lexer)->type == CPP_COLON) + { + cp_lexer_consume_token (parser->lexer); + + e = cp_parser_constant_expression (parser, false, NULL); + e = maybe_constant_value (e); + + if (e == error_mark_node) + { + /* If an error has occurred, then the whole pragma is + considered ill-formed. Thus, no reason to keep + parsing. */ + clauses = error_mark_node; + break; + } + else if (!TREE_TYPE (e) || !TREE_CONSTANT (e) + || !INTEGRAL_TYPE_P (TREE_TYPE (e))) + cp_parser_error (parser, + "step size must be an integer constant"); + else + step_size = e; + } + + /* Use the OMP_CLAUSE_LINEAR, which has the same semantics. */ + tree l = build_omp_clause (loc, OMP_CLAUSE_LINEAR); + OMP_CLAUSE_DECL (l) = decl; + OMP_CLAUSE_LINEAR_STEP (l) = step_size; + OMP_CLAUSE_CHAIN (l) = clauses; + clauses = l; + } + if (cp_lexer_next_token_is (parser->lexer, CPP_COMMA)) + cp_lexer_consume_token (parser->lexer); + else if (cp_lexer_next_token_is (parser->lexer, CPP_CLOSE_PAREN)) + break; + else + { + error_at (cp_lexer_peek_token (parser->lexer)->location, + "expected %<,%> or %<)%> after %qE", decl); + clauses = error_mark_node; + break; + } + } + cp_parser_skip_to_closing_parenthesis (parser, false, false, true); + return clauses; +} + +/* Returns the name of the next clause. If the clause is not + recognized, then PRAGMA_CILK_CLAUSE_NONE is returned and the next + token is not consumed. Otherwise, the appropriate enum from the + pragma_simd_clause is returned and the token is consumed. */ + +static pragma_cilk_clause +cp_parser_cilk_simd_clause_name (cp_parser *parser) +{ + pragma_cilk_clause clause_type; + cp_token *token = cp_lexer_peek_token (parser->lexer); + + if (token->keyword == RID_PRIVATE) + clause_type = PRAGMA_CILK_CLAUSE_PRIVATE; + else if (!token->u.value || token->type != CPP_NAME) + return PRAGMA_CILK_CLAUSE_NONE; + else if (!strcmp (IDENTIFIER_POINTER (token->u.value), "vectorlength")) + clause_type = PRAGMA_CILK_CLAUSE_VECTORLENGTH; + else if (!strcmp (IDENTIFIER_POINTER (token->u.value), "linear")) + clause_type = PRAGMA_CILK_CLAUSE_LINEAR; + else if (!strcmp (IDENTIFIER_POINTER (token->u.value), "firstprivate")) + clause_type = PRAGMA_CILK_CLAUSE_FIRSTPRIVATE; + else if (!strcmp (IDENTIFIER_POINTER (token->u.value), "lastprivate")) + clause_type = PRAGMA_CILK_CLAUSE_LASTPRIVATE; + else if (!strcmp (IDENTIFIER_POINTER (token->u.value), "reduction")) + clause_type = PRAGMA_CILK_CLAUSE_REDUCTION; + else + return PRAGMA_CILK_CLAUSE_NONE; + + cp_lexer_consume_token (parser->lexer); + return clause_type; +} + +/* Parses all the #pragma simd clauses. Returns a list of clauses found. */ + +static tree +cp_parser_cilk_simd_all_clauses (cp_parser *parser, cp_token *pragma_token) +{ + tree clauses = NULL_TREE; + + while (cp_lexer_next_token_is_not (parser->lexer, CPP_PRAGMA_EOL) + && clauses != error_mark_node) + { + pragma_cilk_clause c_kind; + c_kind = cp_parser_cilk_simd_clause_name (parser); + if (c_kind == PRAGMA_CILK_CLAUSE_VECTORLENGTH) + clauses = cp_parser_cilk_simd_vectorlength (parser, clauses); + else if (c_kind == PRAGMA_CILK_CLAUSE_LINEAR) + clauses = cp_parser_cilk_simd_linear (parser, clauses); + else if (c_kind == PRAGMA_CILK_CLAUSE_PRIVATE) + /* Use the OpenMP 4.0 equivalent function. */ + clauses = cp_parser_omp_var_list (parser, OMP_CLAUSE_PRIVATE, clauses); + else if (c_kind == PRAGMA_CILK_CLAUSE_FIRSTPRIVATE) + /* Use the OpenMP 4.0 equivalent function. */ + clauses = cp_parser_omp_var_list (parser, OMP_CLAUSE_FIRSTPRIVATE, + clauses); + else if (c_kind == PRAGMA_CILK_CLAUSE_LASTPRIVATE) + /* Use the OMP 4.0 equivalent function. */ + clauses = cp_parser_omp_var_list (parser, OMP_CLAUSE_LASTPRIVATE, + clauses); + else if (c_kind == PRAGMA_CILK_CLAUSE_REDUCTION) + /* Use the OMP 4.0 equivalent function. */ + clauses = cp_parser_omp_clause_reduction (parser, clauses); + else + { + clauses = error_mark_node; + cp_parser_error (parser, "expected %<#pragma simd%> clause"); + break; + } + } + + cp_parser_skip_to_pragma_eol (parser, pragma_token); + + if (clauses == error_mark_node) + return error_mark_node; + else + return c_finish_cilk_clauses (clauses); +} + +/* Main entry-point for parsing Cilk Plus <#pragma simd> for loops. */ + +static void +cp_parser_cilk_simd_construct (cp_parser *parser, cp_token *pragma_token) +{ + tree clauses = cp_parser_cilk_simd_all_clauses (parser, pragma_token); + + if (clauses == error_mark_node) + return; + + if (cp_lexer_next_token_is_not_keyword (parser->lexer, RID_FOR)) + { + error_at (cp_lexer_peek_token (parser->lexer)->location, + "for statement expected"); + return; + } + + tree sb = begin_omp_structured_block (); + int save = cp_parser_begin_omp_structured_block (parser); + cp_parser_cilk_for (parser, RID_FOR, clauses); + cp_parser_end_omp_structured_block (parser, save); + add_stmt (finish_omp_structured_block (sb)); + return; +} + +/* Parses the initializer of a for/_Cilk_for statement. The initial + value is stored in *INIT, and the inital value's declaration is + stored as DECL_EXPR in *PRE_BODY. */ + +static tree +cp_parser_simd_for_init_statement (cp_parser *parser, tree *init, + tree *pre_body) +{ + cp_token *token = cp_lexer_peek_token (parser->lexer); + location_t loc = cp_lexer_peek_token (parser->lexer)->location; + tree decl = NULL_TREE; + cp_decl_specifier_seq type_specifiers; + tree this_pre_body = push_stmt_list (); + if (token->type == CPP_SEMICOLON) + { + error_at (loc, "expected iteration declaration"); + return error_mark_node; + } + + if (cp_lexer_next_token_is_keyword (parser->lexer, RID_STATIC) + || cp_lexer_next_token_is_keyword (parser->lexer, RID_REGISTER) + || cp_lexer_next_token_is_keyword (parser->lexer, RID_EXTERN) + || cp_lexer_next_token_is_keyword (parser->lexer, RID_MUTABLE) + || cp_lexer_next_token_is_keyword (parser->lexer, RID_THREAD)) + { + error_at (loc, "storage class is not allowed"); + cp_lexer_consume_token (parser->lexer); + } + + cp_parser_parse_tentatively (parser); + cp_parser_type_specifier_seq (parser, true, false, &type_specifiers); + if (cp_parser_parse_definitely (parser)) + { + cp_declarator *cp_decl; + tree asm_spec, attr; + cp_decl = cp_parser_declarator (parser, CP_PARSER_DECLARATOR_NAMED, + NULL, NULL, false); + attr = cp_parser_attributes_opt (parser); + asm_spec = cp_parser_asm_specification_opt (parser); + if (cp_decl == cp_error_declarator) + cp_parser_skip_to_end_of_statement (parser); + else + { + tree pushed_scope, auto_node; + decl = start_decl (cp_decl, &type_specifiers, SD_INITIALIZED, attr, + NULL_TREE, &pushed_scope); + auto_node = type_uses_auto (TREE_TYPE (decl)); + if (cp_lexer_next_token_is_not (parser->lexer, CPP_EQ)) + { + if (cp_lexer_next_token_is (parser->lexer, CPP_OPEN_PAREN)) + error_at (loc, "parenthesized initialization is " + "not allowed in for-loop"); + else + { + if (!cp_parser_require (parser, CPP_EQ, RT_EQ)) + decl = error_mark_node; + } + + *init = error_mark_node; + cp_parser_skip_to_end_of_statement (parser); + } + else if (CLASS_TYPE_P (TREE_TYPE (decl)) || auto_node + || type_dependent_expression_p (decl)) + { + bool is_direct_init, is_non_constant_init; + *init = cp_parser_initializer (parser, &is_direct_init, + &is_non_constant_init); + if (auto_node) + { + TREE_TYPE (decl) + = do_auto_deduction (TREE_TYPE (decl), *init, auto_node); + if (!CLASS_TYPE_P (TREE_TYPE (decl)) + && !type_dependent_expression_p (decl)) + goto non_class; + } + cp_finish_decl (decl, *init, !is_non_constant_init, asm_spec, + LOOKUP_ONLYCONVERTING); + if (CLASS_TYPE_P (TREE_TYPE (decl))) + *init = NULL_TREE; + else + *init = pop_stmt_list (this_pre_body); + this_pre_body = NULL_TREE; + } + else + { + /* Consume the '='. */ + cp_lexer_consume_token (parser->lexer); + *init = cp_parser_assignment_expression (parser, false, NULL); + non_class: + if (TREE_CODE (TREE_TYPE (decl)) == REFERENCE_TYPE) + *init = error_mark_node; + else + cp_finish_decl (decl, NULL_TREE, false, asm_spec, + LOOKUP_ONLYCONVERTING); + if (decl != error_mark_node) + DECL_INITIAL (decl) = (*init || *init != error_mark_node) ? + *init : NULL_TREE; + } + if (pushed_scope) + pop_scope (pushed_scope); + } + } + else + { + cp_id_kind idk; + cp_parser_parse_tentatively (parser); + decl = cp_parser_primary_expression (parser, false, false, + false, &idk); + if (!cp_parser_error_occurred (parser) && decl && DECL_P (decl) + && CLASS_TYPE_P (TREE_TYPE (decl))) + { + tree rhs, new_expr; + // ?? FIXME: I don't see any definition for *init in this + // code path. ?? + gcc_unreachable (); + cp_parser_parse_definitely (parser); + cp_parser_require (parser, CPP_EQ, RT_EQ); + rhs = cp_parser_assignment_expression (parser, false, NULL); + new_expr = build_x_modify_expr (EXPR_LOCATION (rhs), decl, + NOP_EXPR, rhs, + tf_warning_or_error); + finish_expr_stmt (new_expr); + } + else + { + if (decl != error_mark_node) + decl = NULL; + cp_parser_abort_tentative_parse (parser); + *init = cp_parser_expression (parser, false, NULL); + } + } + + if (this_pre_body) + this_pre_body = pop_stmt_list (this_pre_body); + + *pre_body = this_pre_body; + return decl; +} + +/* Top-level function to parse _Cilk_for and the for statement + following <#pragma simd>. */ + +static tree +cp_parser_cilk_for (cp_parser *parser, enum rid for_keyword, tree clauses) +{ + bool valid = true; + tree cond = NULL_TREE; + tree incr_expr = NULL_TREE; + tree init = NULL_TREE, pre_body = NULL_TREE, decl; + location_t loc = cp_lexer_peek_token (parser->lexer)->location; + + gcc_assert (for_keyword == RID_FOR); + + if (!cp_lexer_next_token_is_keyword (parser->lexer, for_keyword)) + { + if (for_keyword == RID_FOR) + cp_parser_error (parser, "for statement expected"); + else + cp_parser_error (parser, "_Cilk_for statement expected"); + return error_mark_node; + } + cp_lexer_consume_token (parser->lexer); + + if (!cp_parser_require (parser, CPP_OPEN_PAREN, RT_OPEN_PAREN)) + { + cp_parser_skip_to_end_of_statement (parser); + return error_mark_node; + } + + /* Parse initialization. */ + if (for_keyword == RID_FOR) + decl = cp_parser_simd_for_init_statement (parser, &init, &pre_body); + + if (decl == error_mark_node) + valid = false; + else if (!decl || (TREE_CODE (decl) != VAR_DECL + && TREE_CODE (decl) != DECL_EXPR)) + { + error_at (loc, "%s-loop initializer does not declare a variable", + for_keyword == RID_FOR ? "for" : "_Cilk_for"); + valid = false; + decl = error_mark_node; + } + else if (!processing_template_decl + && !DECL_NONTRIVIALLY_INITIALIZED_P (decl) + && !DECL_INITIAL (decl) + && !TYPE_NEEDS_CONSTRUCTING (TREE_TYPE (decl))) + { + error_at (loc, "control variable for the %s-loop needs to " + "be initialized", + for_keyword == RID_FOR ? "for" : "_Cilk_for"); + valid = false; + } + if (cp_lexer_next_token_is (parser->lexer, CPP_COMMA)) + { + error_at (loc, "%s-loop initializer cannot have multiple variable " + "declarations", for_keyword == RID_FOR ? "for" : "_Cilk_for"); + cp_parser_skip_to_end_of_statement (parser); + valid = false; + } + + if (!valid) + { + /* Skip to the semicolon ending the init. */ + cp_parser_skip_to_end_of_statement (parser); + } + + /* Parse condition. */ + if (!cp_parser_require (parser, CPP_SEMICOLON, RT_SEMICOLON)) + return error_mark_node; + if (cp_lexer_next_token_is (parser->lexer, CPP_SEMICOLON)) + { + error_at (loc, "missing condition"); + cond = error_mark_node; + } + else + { + cond = cp_parser_condition (parser); + cond = finish_cilk_for_cond (cond); + } + + if (cond == error_mark_node) + valid = false; + cp_parser_consume_semicolon_at_end_of_statement (parser); + + /* Parse increment. */ + if (cp_lexer_next_token_is (parser->lexer, CPP_CLOSE_PAREN)) + { + error_at (loc, "missing increment"); + incr_expr = error_mark_node; + } + else + incr_expr = cp_parser_expression (parser, false, NULL); + + if (incr_expr == error_mark_node) + { + cp_parser_skip_to_closing_parenthesis (parser, true, false, false); + valid = false; + } + + if (!cp_parser_require (parser, CPP_CLOSE_PAREN, RT_CLOSE_PAREN)) + { + cp_parser_skip_to_end_of_statement (parser); + valid = false; + } + + if (!valid) + { + gcc_assert (sorrycount || errorcount); + return error_mark_node; + } + + if (for_keyword == RID_FOR) + { + parser->in_statement = IN_CILK_P_SIMD_FOR; + tree body = push_stmt_list (); + cp_parser_statement (parser, NULL_TREE, false, NULL); + body = pop_stmt_list (body); + + /* Check if the body satisfies all the requirement of a #pragma + simd for body. If it is invalid, then do not make the OpenMP + nodes, just return an error mark node. */ + if (!cpp_validate_cilk_plus_loop (body)) + return error_mark_node; + + return c_finish_cilk_simd_loop (loc, decl, init, cond, incr_expr, + body, clauses); + } + else + { + /* Handle _Cilk_for here when implemented. */ + gcc_unreachable (); + return NULL_TREE; + } +} + #include "gt-cp-parser.h" diff --git a/gcc/cp/parser.h b/gcc/cp/parser.h index 3d8bb742d22..4fbc6558e41 100644 --- a/gcc/cp/parser.h +++ b/gcc/cp/parser.h @@ -292,6 +292,7 @@ typedef struct GTY(()) cp_parser { #define IN_OMP_BLOCK 4 #define IN_OMP_FOR 8 #define IN_IF_STMT 16 +#define IN_CILK_P_SIMD_FOR 32 unsigned char in_statement; /* TRUE if we are presently parsing the body of a switch statement. diff --git a/gcc/cp/semantics.c b/gcc/cp/semantics.c index f8217546b6b..4ee747731cf 100644 --- a/gcc/cp/semantics.c +++ b/gcc/cp/semantics.c @@ -5142,6 +5142,13 @@ finish_omp_taskyield (void) finish_expr_stmt (stmt); } +/* Perform any canonicalization of the conditional in a Cilk for loop. */ +tree +finish_cilk_for_cond (tree cond) +{ + return cp_truthvalue_conversion (cond); +} + /* Begin a __transaction_atomic or __transaction_relaxed statement. If PCOMPOUND is non-null, this is for a function-transaction-block, and we should create an extra compound stmt. */ diff --git a/gcc/gimple-pretty-print.c b/gcc/gimple-pretty-print.c index a698251bb7b..59724f8a93f 100644 --- a/gcc/gimple-pretty-print.c +++ b/gcc/gimple-pretty-print.c @@ -1110,6 +1110,9 @@ dump_gimple_omp_for (pretty_printer *buffer, gimple gs, int spc, int flags) case GF_OMP_FOR_KIND_SIMD: kind = " simd"; break; + case GF_OMP_FOR_KIND_CILKSIMD: + kind = " cilksimd"; + break; default: gcc_unreachable (); } @@ -1138,6 +1141,9 @@ dump_gimple_omp_for (pretty_printer *buffer, gimple gs, int spc, int flags) case GF_OMP_FOR_KIND_SIMD: pp_string (buffer, "#pragma omp simd"); break; + case GF_OMP_FOR_KIND_CILKSIMD: + pp_string (buffer, "#pragma simd"); + break; default: gcc_unreachable (); } diff --git a/gcc/gimple.h b/gcc/gimple.h index 37c37a60588..b07f850115f 100644 --- a/gcc/gimple.h +++ b/gcc/gimple.h @@ -112,7 +112,8 @@ enum gf_mask { GF_OMP_PARALLEL_COMBINED = 1 << 0, GF_OMP_FOR_KIND_MASK = 3 << 0, GF_OMP_FOR_KIND_FOR = 0 << 0, - GF_OMP_FOR_KIND_SIMD = 1 << 0, + GF_OMP_FOR_KIND_SIMD = 2 << 0, + GF_OMP_FOR_KIND_CILKSIMD = 3 << 0, /* True on an GIMPLE_OMP_RETURN statement if the return does not require a thread synchronization via some sort of barrier. The exact barrier diff --git a/gcc/gimplify.c b/gcc/gimplify.c index 7b16f87ce8b..3b09ea827b2 100644 --- a/gcc/gimplify.c +++ b/gcc/gimplify.c @@ -4711,6 +4711,7 @@ is_gimple_stmt (tree t) case OMP_PARALLEL: case OMP_FOR: case OMP_SIMD: + case CILK_SIMD: case OMP_SECTIONS: case OMP_SECTION: case OMP_SINGLE: @@ -6584,7 +6585,8 @@ gimplify_omp_for (tree *expr_p, gimple_seq *pre_p) for_stmt = *expr_p; - simd = TREE_CODE (for_stmt) == OMP_SIMD; + simd = TREE_CODE (for_stmt) == OMP_SIMD + || TREE_CODE (for_stmt) == CILK_SIMD; gimplify_scan_omp_clauses (&OMP_FOR_CLAUSES (for_stmt), pre_p, simd ? ORT_SIMD : ORT_WORKSHARE); @@ -6810,6 +6812,7 @@ gimplify_omp_for (tree *expr_p, gimple_seq *pre_p) { case OMP_FOR: kind = GF_OMP_FOR_KIND_FOR; break; case OMP_SIMD: kind = GF_OMP_FOR_KIND_SIMD; break; + case CILK_SIMD: kind = GF_OMP_FOR_KIND_CILKSIMD; break; default: gcc_unreachable (); } @@ -7752,6 +7755,7 @@ gimplify_expr (tree *expr_p, gimple_seq *pre_p, gimple_seq *post_p, case OMP_FOR: case OMP_SIMD: + case CILK_SIMD: ret = gimplify_omp_for (expr_p, pre_p); break; diff --git a/gcc/omp-low.c b/gcc/omp-low.c index faa01ca9b15..06b322aa3a2 100644 --- a/gcc/omp-low.c +++ b/gcc/omp-low.c @@ -223,7 +223,7 @@ extract_omp_for_data (gimple for_stmt, struct omp_for_data *fd, int i; struct omp_for_data_loop dummy_loop; location_t loc = gimple_location (for_stmt); - bool simd = gimple_omp_for_kind (for_stmt) == GF_OMP_FOR_KIND_SIMD; + bool simd = gimple_omp_for_kind (for_stmt) & GF_OMP_FOR_KIND_SIMD; fd->for_stmt = for_stmt; fd->pre = NULL; @@ -309,6 +309,10 @@ extract_omp_for_data (gimple for_stmt, struct omp_for_data *fd, case LT_EXPR: case GT_EXPR: break; + case NE_EXPR: + gcc_assert (gimple_omp_for_kind (for_stmt) + == GF_OMP_FOR_KIND_CILKSIMD); + break; case LE_EXPR: if (POINTER_TYPE_P (TREE_TYPE (loop->n2))) loop->n2 = fold_build_pointer_plus_hwi_loc (loc, loop->n2, 1); @@ -936,7 +940,7 @@ build_outer_var_ref (tree var, omp_context *ctx) x = build_receiver_ref (var, by_ref, ctx); } else if (gimple_code (ctx->stmt) == GIMPLE_OMP_FOR - && gimple_omp_for_kind (ctx->stmt) == GF_OMP_FOR_KIND_SIMD) + && gimple_omp_for_kind (ctx->stmt) & GF_OMP_FOR_KIND_SIMD) { /* #pragma omp simd isn't a worksharing construct, and can reference even private vars in its linear etc. clauses. */ @@ -1867,7 +1871,7 @@ check_omp_nesting_restrictions (gimple stmt, omp_context *ctx) if (ctx != NULL) { if (gimple_code (ctx->stmt) == GIMPLE_OMP_FOR - && gimple_omp_for_kind (ctx->stmt) == GF_OMP_FOR_KIND_SIMD) + && gimple_omp_for_kind (ctx->stmt) & GF_OMP_FOR_KIND_SIMD) { error_at (gimple_location (stmt), "OpenMP constructs may not be nested inside simd region"); @@ -1877,7 +1881,7 @@ check_omp_nesting_restrictions (gimple stmt, omp_context *ctx) switch (gimple_code (stmt)) { case GIMPLE_OMP_FOR: - if (gimple_omp_for_kind (stmt) == GF_OMP_FOR_KIND_SIMD) + if (gimple_omp_for_kind (stmt) & GF_OMP_FOR_KIND_SIMD) return true; /* FALLTHRU */ case GIMPLE_OMP_SECTIONS: @@ -2381,7 +2385,7 @@ lower_rec_input_clauses (tree clauses, gimple_seq *ilist, gimple_seq *dlist, bool lastprivate_firstprivate = false; int pass; bool is_simd = (gimple_code (ctx->stmt) == GIMPLE_OMP_FOR - && gimple_omp_for_kind (ctx->stmt) == GF_OMP_FOR_KIND_SIMD); + && gimple_omp_for_kind (ctx->stmt) & GF_OMP_FOR_KIND_SIMD); int max_vf = 0; tree lane = NULL_TREE, idx = NULL_TREE; tree ivar = NULL_TREE, lvar = NULL_TREE; @@ -2837,7 +2841,7 @@ lower_rec_input_clauses (tree clauses, gimple_seq *ilist, gimple_seq *dlist, /* Don't add any barrier for #pragma omp simd or #pragma omp distribute. */ if (gimple_code (ctx->stmt) != GIMPLE_OMP_FOR - || gimple_omp_for_kind (ctx->stmt) == GF_OMP_FOR_KIND_FOR) + || gimple_omp_for_kind (ctx->stmt) & GF_OMP_FOR_KIND_FOR) gimplify_and_add (build_omp_barrier (), ilist); } @@ -2916,7 +2920,7 @@ lower_lastprivate_clauses (tree clauses, tree predicate, gimple_seq *stmt_list, } if (gimple_code (ctx->stmt) == GIMPLE_OMP_FOR - && gimple_omp_for_kind (ctx->stmt) == GF_OMP_FOR_KIND_SIMD) + && gimple_omp_for_kind (ctx->stmt) & GF_OMP_FOR_KIND_SIMD) { simduid = find_omp_clause (orig_clauses, OMP_CLAUSE__SIMDUID_); if (simduid) @@ -3011,7 +3015,7 @@ lower_reduction_clauses (tree clauses, gimple_seq *stmt_seqp, omp_context *ctx) /* SIMD reductions are handled in lower_rec_input_clauses. */ if (gimple_code (ctx->stmt) == GIMPLE_OMP_FOR - && gimple_omp_for_kind (ctx->stmt) == GF_OMP_FOR_KIND_SIMD) + && gimple_omp_for_kind (ctx->stmt) & GF_OMP_FOR_KIND_SIMD) return; /* First see if there is exactly one reduction clause. Use OMP_ATOMIC @@ -5697,7 +5701,7 @@ expand_omp_for (struct omp_region *region) original loops from being detected. Fix that up. */ loops_state_set (LOOPS_NEED_FIXUP); - if (gimple_omp_for_kind (fd.for_stmt) == GF_OMP_FOR_KIND_SIMD) + if (gimple_omp_for_kind (fd.for_stmt) & GF_OMP_FOR_KIND_SIMD) expand_omp_simd (region, &fd); else if (fd.sched_kind == OMP_CLAUSE_SCHEDULE_STATIC && !fd.have_ordered @@ -6802,7 +6806,7 @@ execute_expand_omp (void) static bool gate_expand_omp (void) { - return (flag_openmp != 0 && !seen_error ()); + return ((flag_openmp || flag_enable_cilkplus) && !seen_error ()); } struct gimple_opt_pass pass_expand_omp = @@ -7953,7 +7957,7 @@ execute_lower_omp (void) /* This pass always runs, to provide PROP_gimple_lomp. But there is nothing to do unless -fopenmp is given. */ - if (flag_openmp == 0) + if (!flag_openmp && !flag_enable_cilkplus) return 0; all_contexts = splay_tree_new (splay_tree_compare_pointers, 0, @@ -8056,12 +8060,33 @@ diagnose_sb_0 (gimple_stmt_iterator *gsi_p, error ("invalid entry to OpenMP structured block"); #endif + bool cilkplus_block = false; + if (flag_enable_cilkplus) + { + if ((branch_ctx + && gimple_code (branch_ctx) == GIMPLE_OMP_FOR + && gimple_omp_for_kind (branch_ctx) == GF_OMP_FOR_KIND_CILKSIMD) + || (gimple_code (label_ctx) == GIMPLE_OMP_FOR + && gimple_omp_for_kind (label_ctx) == GF_OMP_FOR_KIND_CILKSIMD)) + cilkplus_block = true; + } + /* If it's obvious we have an invalid entry, be specific about the error. */ if (branch_ctx == NULL) - error ("invalid entry to OpenMP structured block"); + { + if (cilkplus_block) + error ("invalid entry to Cilk Plus structured block"); + else + error ("invalid entry to OpenMP structured block"); + } else - /* Otherwise, be vague and lazy, but efficient. */ - error ("invalid branch to/from an OpenMP structured block"); + { + /* Otherwise, be vague and lazy, but efficient. */ + if (cilkplus_block) + error ("invalid branch to/from a Cilk Plus structured block"); + else + error ("invalid branch to/from an OpenMP structured block"); + } gsi_replace (gsi_p, gimple_build_nop (), false); return true; @@ -8244,7 +8269,7 @@ diagnose_omp_structured_block_errors (void) static bool gate_diagnose_omp_blocks (void) { - return flag_openmp != 0; + return flag_openmp || flag_enable_cilkplus; } struct gimple_opt_pass pass_diagnose_omp_blocks = diff --git a/gcc/testsuite/c-c++-common/cilk-plus/PS/body.c b/gcc/testsuite/c-c++-common/cilk-plus/PS/body.c new file mode 100644 index 00000000000..e8e2066de43 --- /dev/null +++ b/gcc/testsuite/c-c++-common/cilk-plus/PS/body.c @@ -0,0 +1,33 @@ +/* { dg-do compile } */ +/* { dg-options "-fcilkplus -fopenmp" } */ + +int *a, *b, c; +void *jmpbuf[10]; + +void foo() +{ + int j; + +#pragma simd + for (int i=0; i < 1000; ++i) + { + if (c == 6) + __builtin_setjmp (jmpbuf); /* { dg-error "calls to setjmp are not allowed" } */ + a[i] = b[i]; + } + +#pragma simd + for (int i=0; i < 1000; ++i) + { + if (c==5) + break; /* { dg-error "break statement within" } */ + } + +#pragma simd + for (int i=0; i < 1000; ++i) + { +#pragma omp for /* { dg-error "OpenMP statements are not allowed" } */ + for (j=0; j < 1000; ++j) + a[i] = b[i]; + } +} diff --git a/gcc/testsuite/c-c++-common/cilk-plus/PS/clauses1.c b/gcc/testsuite/c-c++-common/cilk-plus/PS/clauses1.c new file mode 100644 index 00000000000..6d84791c605 --- /dev/null +++ b/gcc/testsuite/c-c++-common/cilk-plus/PS/clauses1.c @@ -0,0 +1,76 @@ +/* { dg-do compile } */ +/* { dg-options "-O3 -Werror -Wunknown-pragmas -fcilkplus" } */ + +volatile int *a, *b; + +void foo() +{ + int i, j, k; + +#pragma simd assert /* { dg-error "expected '#pragma simd' clause" } */ + for (i=0; i < 100; ++i) + a[i] = b[i]; + +#pragma simd vectorlength /* { dg-error "expected '\\('" } */ + for (int i=0; i < 1000; ++i) + a[i] = b[j]; + +#pragma simd vectorlength /* { dg-error "expected '\\('" } */ + for (int i=0; i < 1000; ++i) + a[i] = b[j]; + +#pragma simd vectorlength(sizeof (a) == sizeof (float) ? 4 : 8) + for (int i=0; i < 1000; ++i) + a[i] = b[j]; + +#pragma simd vectorlength(4,8) /* { dg-error "expected '\\)'" } */ + for (int i=0; i < 1000; ++i) + a[i] = b[j]; + +#pragma simd vectorlength(i) /* { dg-error "\(vectorlength must be an integer\|in a constant\)" } */ + for (int i=0; i < 1000; ++i) + a[i] = b[j]; + +#pragma simd linear(35) /* { dg-error "expected identifier" } */ + for (int i=0; i < 1000; ++i) + a[i] = b[j]; + +#pragma simd linear(blah) /* { dg-error "'blah' \(undeclared\|has not been\)" } */ + for (int i=0; i < 1000; ++i) + a[i] = b[j]; + +#pragma simd linear(j, 36, k) /* { dg-error "expected" } */ + for (int i=0; i < 1000; ++i) + a[i] = b[j]; + +#pragma simd linear(i, j) + for (int i=0; i < 1000; ++i) + a[i] = b[j]; + +#pragma simd linear(i) + for (int i=0; i < 1000; ++i) + a[i] = b[j]; + +#pragma simd linear(i : 4) + for (int i=0; i < 1000; ++i) + a[i] = b[j]; + +#pragma simd linear(i : 2, j : 4, k) + for (int i=0; i < 1000; ++i) + a[i] = b[j]; + +#pragma simd linear(j : sizeof (a) == sizeof (float) ? 4 : 8) + for (int i=0; i < 1000; ++i) + a[i] = b[j]; + + // And now everyone in unison! +#pragma simd linear(j : 4) vectorlength(4) + for (int i=0; i < 1000; ++i) + a[i] = b[j]; + +#pragma simd linear(blah2, 36) + /* { dg-error "'blah2' \(undeclared\|has not been\)" "undeclared" { target *-*-* } 71 } */ + /* { dg-error "expected" "expected" { target *-*-* } 71 } */ + for (int i=0; i < 1000; ++i) + a[i] = b[j]; +} diff --git a/gcc/testsuite/c-c++-common/cilk-plus/PS/clauses2.c b/gcc/testsuite/c-c++-common/cilk-plus/PS/clauses2.c new file mode 100644 index 00000000000..71589c2b178 --- /dev/null +++ b/gcc/testsuite/c-c++-common/cilk-plus/PS/clauses2.c @@ -0,0 +1,18 @@ +/* { dg-do compile } */ +/* { dg-options "-O3 -fdump-tree-original -fcilkplus" } */ + +volatile int *a, *b; + +void foo() +{ + int j, k; + +#pragma simd linear(j : 4, k) vectorlength(4) + for (int i=0; i < 1000; ++i) + a[i] = b[j]; +} + +/* { dg-final { scan-tree-dump-times "linear\\(j:4\\)" 1 "original" } } */ +/* { dg-final { scan-tree-dump-times "linear\\(k:1\\)" 1 "original" } } */ +/* { dg-final { scan-tree-dump-times "safelen\\(4\\)" 1 "original" } } */ +/* { dg-final { cleanup-tree-dump "original" } } */ diff --git a/gcc/testsuite/c-c++-common/cilk-plus/PS/clauses3.c b/gcc/testsuite/c-c++-common/cilk-plus/PS/clauses3.c new file mode 100644 index 00000000000..579b718a01c --- /dev/null +++ b/gcc/testsuite/c-c++-common/cilk-plus/PS/clauses3.c @@ -0,0 +1,39 @@ +/* { dg-do compile } */ +/* { dg-options "-O3 -fcilkplus" } */ + +#define N 1000 + +int A[N], B[N], C[N]; +int main (void) +{ +#pragma simd private (B) linear(B:1) /* { dg-error "more than one clause" } */ + for (int ii = 0; ii < N; ii++) + { + A[ii] = B[ii] + C[ii]; + } + +#pragma simd private (B, C) linear(B:1) /* { dg-error "more than one clause" } */ + for (int ii = 0; ii < N; ii++) + { + A[ii] = B[ii] + C[ii]; + } + +#pragma simd private (B) linear(C:2, B:1) /* { dg-error "more than one clause" } */ + for (int ii = 0; ii < N; ii++) + { + A[ii] = B[ii] + C[ii]; + } + +#pragma simd reduction (+:B) linear(B:1) /* { dg-error "more than one clause" } */ + for (int ii = 0; ii < N; ii++) + { + A[ii] = B[ii] + C[ii]; + } + +#pragma simd reduction (+:B) linear(B) /* { dg-error "more than one clause" } */ + for (int ii = 0; ii < N; ii++) + { + A[ii] = B[ii] + C[ii]; + } + return 0; +} diff --git a/gcc/testsuite/c-c++-common/cilk-plus/PS/for1.c b/gcc/testsuite/c-c++-common/cilk-plus/PS/for1.c new file mode 100644 index 00000000000..04773d12755 --- /dev/null +++ b/gcc/testsuite/c-c++-common/cilk-plus/PS/for1.c @@ -0,0 +1,139 @@ +/* { dg-do compile } */ +/* { dg-options "-O3 -fcilkplus" } */ + +int *a, *b, *c; +int something; + +void foo() +{ + int i, j; + + // Declaration and initialization is allowed. +#pragma simd + for (int i=0; i < 1000; i++) + a[i] = b[j]; + + // Empty initialization is not allowed. +#pragma simd + for (; i < 5; ++i) // { dg-error "expected iteration decl" } + a[i] = i; + + // Empty condition is not allowed. +#pragma simd + for (int i=0; ; ++i) /* { dg-error "missing condition" } */ + a[i] = i; + + // Empty increment is not allowed. +#pragma simd + for (int i=0; i < 1234; ) /* { dg-error "missing increment" } */ + a[i] = i*2; + +#pragma simd + i = 5; /* { dg-error "for statement expected" } */ + + // Initialization variables must be either integral or pointer types. + struct S { + int i; + }; +#pragma simd + for (struct S ss = { 0 }; ss.i <= 1000; ++ss.i) /* { dg-error "initialization variable must be of integral or pointer type" } */ + a[ss.i] = b[ss.i]; + + #pragma simd + for (float f=0.0; f < 15.0; ++f) /* { dg-error "must be of integral" } */ + a[(int)f] = (int) f; + + // Pointers are OK. + #pragma simd + for (int *i=c; i < &c[100]; ++i) + *a = '5'; + + // Condition of '==' is not allowed. +#pragma simd + for (int i=j; i == 5; ++i) /* { dg-error "invalid controlling predicate" } */ + a[i] = b[i]; + + // The LHS or RHS of the condition must be the initialization variable. +#pragma simd + for (int i=0; i+j < 1234; ++i) /* { dg-error "invalid controlling predicate" } */ + a[i] = b[i]; + + // Likewise. +#pragma simd + for (int i=0; 1234 < i + j; ++i) /* { dg-error "invalid controlling predicate" } */ + a[i] = b[i]; + + // Likewise, this is ok. +#pragma simd + for (int i=0; 1234 + j < i; ++i) + a[i] = b[i]; + + // According to the CilkPlus forum, casts are not allowed, even if + // they are no-ops. +#pragma simd + for (int i=0; (char)i < 1234; ++i) /* { dg-error "invalid controlling predicate" } */ + a[i] = b[i]; + +#pragma simd + for (int i=255; i != something; --i) + a[i] = b[i]; + + // This condition gets folded into "i != 0" by + // c_parser_cilk_for_statement(). This is allowed as per the "!=" + // allowance above. +#pragma simd + for (int i=100; i; --i) + a[i] = b[i]; + +#pragma simd + for (int i=100; i != 5; i += something) + a[i] = b[i]; + + // Increment must be on the induction variable. +#pragma simd + for (int i=0; i < 100; j++) /* { dg-error "invalid increment expression" } */ + a[i] = b[i]; + + // Likewise. +#pragma simd + for (int i=0; i < 100; j = i + 1) /* { dg-error "invalid increment expression" } */ + a[i] = b[i]; + + // Likewise. +#pragma simd + for (int i=0; i < 100; i = j + 1) /* { dg-error "invalid increment expression" } */ + a[i] = b[i]; + +#pragma simd + for (int i=0; i < 100; i = i + 5) + a[i] = b[i]; + + // Only PLUS and MINUS increments are allowed. +#pragma simd + for (int i=0; i < 100; i *= 5) /* { dg-error "invalid increment expression" } */ + a[i] = b[i]; + +#pragma simd + for (int i=0; i < 100; i -= j) + a[i] = b[i]; + +#pragma simd + for (int i=0; i < 100; i = i + j) + a[i] = b[i]; + +#pragma simd + for (int i=0; i < 100; i = j + i) + a[i] = b[i]; + +#pragma simd + for (int i=0; i < 100; ++i, ++j) /* { dg-error "invalid increment expression" } */ + a[i] = b[i]; + +#pragma simd + for (int *point=0; point < b; ++point) + *point = 555; + +#pragma simd + for (int *point=0; point > b; --point) + *point = 555; +} diff --git a/gcc/testsuite/c-c++-common/cilk-plus/PS/for3.c b/gcc/testsuite/c-c++-common/cilk-plus/PS/for3.c new file mode 100644 index 00000000000..86606275ac4 --- /dev/null +++ b/gcc/testsuite/c-c++-common/cilk-plus/PS/for3.c @@ -0,0 +1,8 @@ +/* { dg-do compile } */ +/* { dg-options "-O3 -fcilkplus" } */ + +#pragma simd /* { dg-error "must be inside a function" } */ + +void foo() +{ +} diff --git a/gcc/testsuite/c-c++-common/cilk-plus/PS/for4.c b/gcc/testsuite/c-c++-common/cilk-plus/PS/for4.c new file mode 100644 index 00000000000..2da8235f319 --- /dev/null +++ b/gcc/testsuite/c-c++-common/cilk-plus/PS/for4.c @@ -0,0 +1,14 @@ +/* { dg-do compile } */ +/* { dg-options "-O3 -fcilkplus" } */ + +int *a, *c; + +void foo() +{ + int i, j; + + // Pointers are OK. + #pragma simd + for (int *i=c; i < c; ++i) + *a = '5'; +} diff --git a/gcc/testsuite/c-c++-common/cilk-plus/PS/for5.c b/gcc/testsuite/c-c++-common/cilk-plus/PS/for5.c new file mode 100644 index 00000000000..7075a44718e --- /dev/null +++ b/gcc/testsuite/c-c++-common/cilk-plus/PS/for5.c @@ -0,0 +1,11 @@ +/* { dg-do compile } */ +/* { dg-options "-O3 -fcilkplus" } */ + +int *a, *b; + +void foo() +{ +#pragma simd + for (int i=100; i; --i) + a[i] = b[i]; +} diff --git a/gcc/testsuite/c-c++-common/cilk-plus/PS/p_simd_test1.c b/gcc/testsuite/c-c++-common/cilk-plus/PS/p_simd_test1.c new file mode 100644 index 00000000000..43a359a9442 --- /dev/null +++ b/gcc/testsuite/c-c++-common/cilk-plus/PS/p_simd_test1.c @@ -0,0 +1,36 @@ +/* { dg-do run } */ +/* { dg-options "-O3 -fcilkplus" } */ + +#include <stdio.h> + +#define ARRAY_SIZE (256) +int a[ARRAY_SIZE]; + +__attribute__((noinline)) +int addit (int *arr, int N) +{ + int s=0; +#pragma simd reduction (+:s) + for (int i = 0; i < N; i++) + s += arr[i]; + return s; +} + +int main () { + int i, s = 0, r = 0; + for (i = 0; i < ARRAY_SIZE; i++) + { + a[i] = i; + } + + s = addit (a, ARRAY_SIZE); + + for (i = 0; i < ARRAY_SIZE; i++) + r += i; + + if (s == r) + return 0; + else + return 1; + return 0; +} diff --git a/gcc/testsuite/c-c++-common/cilk-plus/PS/p_simd_test2.c b/gcc/testsuite/c-c++-common/cilk-plus/PS/p_simd_test2.c new file mode 100644 index 00000000000..fe51a2916a1 --- /dev/null +++ b/gcc/testsuite/c-c++-common/cilk-plus/PS/p_simd_test2.c @@ -0,0 +1,41 @@ +/* { dg-do run } */ +/* { dg-options "-O3 -fcilkplus" } */ + +#define N 256 +#if HAVE_IO +#include <stdio.h> +#endif +#include <malloc.h> + +int +reduction_simd (int *a) +{ + int s = 0; + +#pragma simd reduction (+:s) + for (int i = 0; i < N; i++) + { + s += a[i]; + } + + return s; +} + +int +main () +{ + int *a = (int *) malloc (N * sizeof (int)); + int i, s = (N - 1) * N / 2; + + for (i = 0; i < N; i++) + { + a[i] = i; + } +#if HAVE_IO + printf ("%d, %d\n", s, reduction_simd (a)); +#endif + if (s == reduction_simd (a)) + return 0; + else + return 1; +} diff --git a/gcc/testsuite/c-c++-common/cilk-plus/PS/reduction_ex.c b/gcc/testsuite/c-c++-common/cilk-plus/PS/reduction_ex.c new file mode 100644 index 00000000000..920b6db1331 --- /dev/null +++ b/gcc/testsuite/c-c++-common/cilk-plus/PS/reduction_ex.c @@ -0,0 +1,36 @@ +/* { dg-do run } */ +/* { dg-options "-O3 -fcilkplus" } */ + +int argc = 1; + +/* This is a simple vectorization, it checks if check_off_reduction_var works + and it also checks if it can vectorize this loop in func correctly. */ +#define N 1000 + +int func (int *p, int *q) { + int x = 0; +#pragma simd reduction (+:x) + for (int ii = 0; ii < N; ii++) { + x += (q[ii] + p[ii]); + } + return x; + +} + +int main () +{ + int ii = 0, x; + int Array[N], Array2[N]; + + for (ii = 0; ii < N; ii++) + { + Array[ii] = 5 + argc; + Array2[ii] = argc; + } + x = func (Array, Array2); + + if (x != N * 7) + return 1; + return 0; +} + diff --git a/gcc/testsuite/c-c++-common/cilk-plus/PS/run-1.c b/gcc/testsuite/c-c++-common/cilk-plus/PS/run-1.c new file mode 100644 index 00000000000..c8fe1c762bc --- /dev/null +++ b/gcc/testsuite/c-c++-common/cilk-plus/PS/run-1.c @@ -0,0 +1,28 @@ +/* { dg-do run } */ +/* { dg-options "-fcilkplus -O3" } */ + +#include <stdlib.h> + +#define N 4 + +float f1[] = { 2.0, 3.0, 4.0, 5.0 }; +float f2[] = { 1.0, 6.0, -1.0, -2.0 }; +float res[] = { 3.0, 9.0, 3.0, 3.0 }; + +__attribute__((noinline)) +void verify (float *sum) +{ + for (int i=0; i < N; ++i) + if (sum[i] != res[i]) + abort (); +} + +int main() +{ + float sum[N]; +#pragma simd + for (int i=0; i < N; ++i) + sum[i] = f1[i] + f2[i]; + verify (sum); + return 0; +} diff --git a/gcc/testsuite/c-c++-common/cilk-plus/PS/safelen.c b/gcc/testsuite/c-c++-common/cilk-plus/PS/safelen.c new file mode 100644 index 00000000000..2c59de9b02d --- /dev/null +++ b/gcc/testsuite/c-c++-common/cilk-plus/PS/safelen.c @@ -0,0 +1,14 @@ +/* { dg-do compile } */ +/* { dg-options "-O3 -fdump-tree-gimple -fcilkplus" } */ + +int *a, *b; + +void foo() +{ +#pragma simd vectorlength(8) + for (int i=0; i < 1000; ++i) + a[i] = b[i]; +} + +/* { dg-final { scan-tree-dump-times "safelen\\(8\\)" 1 "gimple" } } */ +/* { dg-final { cleanup-tree-dump "gimple" } } */ diff --git a/gcc/testsuite/c-c++-common/cilk-plus/PS/vectorlength.c b/gcc/testsuite/c-c++-common/cilk-plus/PS/vectorlength.c new file mode 100644 index 00000000000..9aa4a68290d --- /dev/null +++ b/gcc/testsuite/c-c++-common/cilk-plus/PS/vectorlength.c @@ -0,0 +1,21 @@ +/* { dg-do compile } */ +/* { dg-options "-O3 -fcilkplus" } */ + +volatile int *a, *b, N; +typedef int tint; +struct someclass { + int a; + char b; + int *p; +}; + +void foo() +{ +#pragma simd vectorlength(4) vectorlength(8) /* { dg-error "too many 'vectorlength' clauses" } */ + for (int i=0; i < N; ++i) + a[i] = b[i]; + +#pragma simd vectorlength(3) /* { dg-error "must be a power of 2" } */ + for (int i=0; i < N; ++i) + a[i] = b[i]; +} diff --git a/gcc/testsuite/g++.dg/cilk-plus/cilk-plus.exp b/gcc/testsuite/g++.dg/cilk-plus/cilk-plus.exp index a1535290a5c..3accc992343 100644 --- a/gcc/testsuite/g++.dg/cilk-plus/cilk-plus.exp +++ b/gcc/testsuite/g++.dg/cilk-plus/cilk-plus.exp @@ -16,10 +16,16 @@ # Written by Balaji V. Iyer <balaji.v.iyer@intel.com> - load_lib g++-dg.exp dg-init +# Run the tests that are shared with C. +g++-dg-runtest [lsort [glob -nocomplain $srcdir/c-c++-common/cilk-plus/PS/*.c]] "" +# Run the C++ only tests. +g++-dg-runtest [lsort [glob -nocomplain $srcdir/$subdir/*.C]] "" +dg-finish + +dg-init dg-runtest [lsort [glob -nocomplain $srcdir/c-c++-common/cilk-plus/AN/*.c]] " -fcilkplus" " " dg-runtest [lsort [glob -nocomplain $srcdir/c-c++-common/cilk-plus/AN/*.c]] " -O0 -fcilkplus" " " dg-runtest [lsort [glob -nocomplain $srcdir/c-c++-common/cilk-plus/AN/*.c]] " -O1 -fcilkplus" " " diff --git a/gcc/testsuite/g++.dg/cilk-plus/for.C b/gcc/testsuite/g++.dg/cilk-plus/for.C new file mode 100644 index 00000000000..2295d214620 --- /dev/null +++ b/gcc/testsuite/g++.dg/cilk-plus/for.C @@ -0,0 +1,12 @@ +/* { dg-do compile } */ +/* { dg-options "-ftree-vectorize -fcilkplus" } */ + +int *a, *b; + +void foo() +{ + int i; +#pragma simd + for (i=0; i < 10000; ++i) /* { dg-error "initializer does not declare a var" } */ + a[i] = b[i]; +} diff --git a/gcc/testsuite/g++.dg/cilk-plus/for2.C b/gcc/testsuite/g++.dg/cilk-plus/for2.C new file mode 100644 index 00000000000..d30e05787e4 --- /dev/null +++ b/gcc/testsuite/g++.dg/cilk-plus/for2.C @@ -0,0 +1,26 @@ +/* { dg-do compile } */ +/* { dg-options "-O3 -fcilkplus" } */ + +// Test storage classes in the initialization of a <#pragma simd> for +// loop. + +int *a, *b; + +void foo() +{ +#pragma simd + for (static int tt=5; tt < 10; ++tt) /* { dg-error "storage class is not allowed" } */ + a[tt] = b[tt]; + +#pragma simd + for (extern int var=0; var < 1000; ++var) /* { dg-error "storage class is not allowed" } */ + a[var] = var; + +#pragma simd + for (register int regj = 0; regj < 1000; ++regj) /* { dg-error "storage class is not allowed" } */ + b[regj] = a[regj] * 2; + +#pragma simd + for (volatile int vj=0; vj<1000; ++vj) /* { dg-error "induction variable cannot be volatile" } */ + a[vj] = b[vj]; +} diff --git a/gcc/testsuite/g++.dg/dg.exp b/gcc/testsuite/g++.dg/dg.exp index 710218e67c5..e9d0428ffee 100644 --- a/gcc/testsuite/g++.dg/dg.exp +++ b/gcc/testsuite/g++.dg/dg.exp @@ -49,6 +49,7 @@ set tests [prune $tests $srcdir/$subdir/tree-prof/*] set tests [prune $tests $srcdir/$subdir/torture/*] set tests [prune $tests $srcdir/$subdir/graphite/*] set tests [prune $tests $srcdir/$subdir/tm/*] +set tests [prune $tests $srcdir/$subdir/cilk-plus/*] set tests [prune $tests $srcdir/$subdir/guality/*] set tests [prune $tests $srcdir/$subdir/simulate-thread/*] set tests [prune $tests $srcdir/$subdir/asan/*] diff --git a/gcc/testsuite/gcc.dg/cilk-plus/auto.c b/gcc/testsuite/gcc.dg/cilk-plus/auto.c new file mode 100644 index 00000000000..253acee1e08 --- /dev/null +++ b/gcc/testsuite/gcc.dg/cilk-plus/auto.c @@ -0,0 +1,17 @@ +/* { dg-do compile } */ + +int *a, *b; + +void foo() +{ + // This seems like it should be ok. + // Must check with standards people. +#pragma simd + for (auto int autoi = 0; autoi < 1000; ++autoi) + b[autoi] = a[autoi] * 2; + // Similarly here. + auto int autoj; +#pragma simd + for (auto int autoj = 0; autoj < 1000; ++autoj) + b[autoj] = a[autoj] * 2; +} diff --git a/gcc/testsuite/gcc.dg/cilk-plus/cilk-plus.exp b/gcc/testsuite/gcc.dg/cilk-plus/cilk-plus.exp index 59b23056c72..e109c717ad3 100644 --- a/gcc/testsuite/gcc.dg/cilk-plus/cilk-plus.exp +++ b/gcc/testsuite/gcc.dg/cilk-plus/cilk-plus.exp @@ -20,6 +20,13 @@ load_lib gcc-dg.exp dg-init + +# Run the tests that are shared with C++. +dg-runtest [lsort [glob -nocomplain $srcdir/c-c++-common/cilk-plus/PS/*.c]] " -ftree-vectorize -fcilkplus -std=c99" " " +# Run the C-only tests. +dg-runtest [lsort [glob -nocomplain $srcdir/$subdir/*.c]] \ + "-ftree-vectorize -fcilkplus -std=c99" " " + dg-runtest [lsort [glob -nocomplain $srcdir/c-c++-common/cilk-plus/AN/*.c]] " -fcilkplus" " " dg-runtest [lsort [glob -nocomplain $srcdir/c-c++-common/cilk-plus/AN/*.c]] " -O0 -fcilkplus" " " dg-runtest [lsort [glob -nocomplain $srcdir/c-c++-common/cilk-plus/AN/*.c]] " -O1 -fcilkplus" " " diff --git a/gcc/testsuite/gcc.dg/cilk-plus/for1.c b/gcc/testsuite/gcc.dg/cilk-plus/for1.c new file mode 100644 index 00000000000..4fb534286d9 --- /dev/null +++ b/gcc/testsuite/gcc.dg/cilk-plus/for1.c @@ -0,0 +1,12 @@ +/* { dg-do compile } */ + +int *a, *b, *c; + +void foo() +{ + int i, j; + // The initialization shall declare or initialize a *SINGLE* variable. +#pragma simd + for (i=0, j=5; i < 1000; i++) // { dg-error "expected ';' before ','" } + a[i] = b[j]; +} diff --git a/gcc/testsuite/gcc.dg/cilk-plus/for2.c b/gcc/testsuite/gcc.dg/cilk-plus/for2.c new file mode 100644 index 00000000000..dc0a41e4be5 --- /dev/null +++ b/gcc/testsuite/gcc.dg/cilk-plus/for2.c @@ -0,0 +1,66 @@ +/* { dg-do compile } */ +/* { dg-options "-O3 -fcilkplus" } */ + +// Test storage classes in the initialization of a <#pragma simd> for +// loop. + +int *a, *b; + +void foo() +{ +#pragma simd + for (static int foo=5; foo < 10; ++foo) + a[foo] = b[foo]; + /* { dg-error "declaration of static variable" "storage class1" { target *-*-* } 12 } */ + /* { dg-error "induction variable cannot be static" "storage class2" { target *-*-* } 12 } */ + + static int bar; +#pragma simd + for (bar=0; bar < 1000; ++bar) /* { dg-error "induction variable cannot be static" } */ + a[bar] = bar; + +#pragma simd + for (extern int var=0; var < 1000; ++var) + a[var] = var; + /* { dg-error "has both 'extern' and initializer" "extern" { target *-*-* } 23 } */ + /* { dg-error "declaration of static variable" "" { target *-*-* } 23 } */ + /* { dg-error "induction variable cannot be static" "" { target *-*-* } 23 } */ + + extern int extvar; +#pragma simd + for (extvar = 0; extvar < 1000; ++extvar) /* { dg-error "induction variable cannot be extern" } */ + b[extvar] = a[extvar]; + + // This seems like it should be ok. + // Must check with standards people. +#pragma simd + for (auto int autoi = 0; autoi < 1000; ++autoi) + b[autoi] = a[autoi] * 2; + // Similarly here. + auto int autoj; +#pragma simd + for (auto int autoj = 0; autoj < 1000; ++autoj) + b[autoj] = a[autoj] * 2; + + register int regi; +#pragma simd + for (regi = 0; regi < 1000; ++regi) /* { dg-error "induction variable cannot be declared register" } */ + b[regi] = a[regi] * 2; + +#pragma simd + for (register int regj = 0; regj < 1000; ++regj) /* { dg-error "induction variable cannot be declared register" } */ + b[regj] = a[regj] * 2; + + volatile int vi; +#pragma simd + for (vi=0; vi<1000; ++vi) /* { dg-error "induction variable cannot be volatile" } */ + a[vi] = b[vi]; + +#pragma simd + for (volatile int vj=0; vj<1000; ++vj) /* { dg-error "induction variable cannot be volatile" } */ + a[vj] = b[vj]; + +#pragma simd + for (const int ci=0; ci<1000; ++ci) /* { dg-error "increment of read-only var" } */ + a[ci] = b[ci]; +} diff --git a/gcc/testsuite/gcc.dg/cilk-plus/jump.c b/gcc/testsuite/gcc.dg/cilk-plus/jump.c new file mode 100644 index 00000000000..9ec3293cc97 --- /dev/null +++ b/gcc/testsuite/gcc.dg/cilk-plus/jump.c @@ -0,0 +1,27 @@ +/* { dg-do compile } */ +/* { dg-options "-fcilkplus" } */ + +int *a, *b, c; + +void foo() +{ +#pragma simd + for (int i=0; i < 1000; ++i) + { + a[i] = b[i]; + if (c == 5) + return; /* { dg-error "invalid branch to.from a Cilk" } */ + } +} + +void bar() +{ +#pragma simd + for (int i=0; i < 1000; ++i) + { + lab: + a[i] = b[i]; + } + if (c == 6) + goto lab; /* { dg-error "invalid entry to Cilk Plus" } */ +} diff --git a/gcc/tree-pretty-print.c b/gcc/tree-pretty-print.c index b2d32fa805e..bfab7372f6b 100644 --- a/gcc/tree-pretty-print.c +++ b/gcc/tree-pretty-print.c @@ -2211,6 +2211,10 @@ dump_generic_node (pretty_printer *buffer, tree node, int spc, int flags, pp_string (buffer, "#pragma omp simd"); goto dump_omp_loop; + case CILK_SIMD: + pp_string (buffer, "#pragma simd"); + goto dump_omp_loop; + dump_omp_loop: dump_omp_clauses (buffer, OMP_FOR_CLAUSES (node), spc, flags); diff --git a/gcc/tree.def b/gcc/tree.def index f825aad5355..552c7046283 100644 --- a/gcc/tree.def +++ b/gcc/tree.def @@ -1034,6 +1034,10 @@ DEFTREECODE (OMP_FOR, "omp_for", tcc_statement, 6) Operands like for OMP_FOR. */ DEFTREECODE (OMP_SIMD, "omp_simd", tcc_statement, 6) +/* Cilk Plus - #pragma simd [clause1 ... clauseN] + Operands like for OMP_FOR. */ +DEFTREECODE (CILK_SIMD, "cilk_simd", tcc_statement, 6) + /* OpenMP - #pragma omp sections [clause1 ... clauseN] Operand 0: OMP_SECTIONS_BODY: Sections body. Operand 1: OMP_SECTIONS_CLAUSES: List of clauses. */ diff --git a/gcc/tree.h b/gcc/tree.h index b902e39201a..74ec261e6ae 100644 --- a/gcc/tree.h +++ b/gcc/tree.h @@ -1792,12 +1792,13 @@ extern void protected_set_expr_location (tree, location_t); #define OMP_TASKREG_BODY(NODE) TREE_OPERAND (OMP_TASKREG_CHECK (NODE), 0) #define OMP_TASKREG_CLAUSES(NODE) TREE_OPERAND (OMP_TASKREG_CHECK (NODE), 1) -#define OMP_FOR_BODY(NODE) TREE_OPERAND (OMP_FOR_CHECK (NODE), 0) -#define OMP_FOR_CLAUSES(NODE) TREE_OPERAND (OMP_FOR_CHECK (NODE), 1) -#define OMP_FOR_INIT(NODE) TREE_OPERAND (OMP_FOR_CHECK (NODE), 2) -#define OMP_FOR_COND(NODE) TREE_OPERAND (OMP_FOR_CHECK (NODE), 3) -#define OMP_FOR_INCR(NODE) TREE_OPERAND (OMP_FOR_CHECK (NODE), 4) -#define OMP_FOR_PRE_BODY(NODE) TREE_OPERAND (OMP_FOR_CHECK (NODE), 5) +#define OMP_LOOP_CHECK(NODE) TREE_RANGE_CHECK (NODE, OMP_FOR, CILK_SIMD) +#define OMP_FOR_BODY(NODE) TREE_OPERAND (OMP_LOOP_CHECK (NODE), 0) +#define OMP_FOR_CLAUSES(NODE) TREE_OPERAND (OMP_LOOP_CHECK (NODE), 1) +#define OMP_FOR_INIT(NODE) TREE_OPERAND (OMP_LOOP_CHECK (NODE), 2) +#define OMP_FOR_COND(NODE) TREE_OPERAND (OMP_LOOP_CHECK (NODE), 3) +#define OMP_FOR_INCR(NODE) TREE_OPERAND (OMP_LOOP_CHECK (NODE), 4) +#define OMP_FOR_PRE_BODY(NODE) TREE_OPERAND (OMP_LOOP_CHECK (NODE), 5) #define OMP_SECTIONS_BODY(NODE) TREE_OPERAND (OMP_SECTIONS_CHECK (NODE), 0) #define OMP_SECTIONS_CLAUSES(NODE) TREE_OPERAND (OMP_SECTIONS_CHECK (NODE), 1) |