summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorAldy Hernandez <aldyh@redhat.com>2013-07-05 15:08:07 -0700
committerAldy Hernandez <aldyh@redhat.com>2013-07-09 08:10:06 -0700
commit564a9fa14ef114c12a4c070a92abf9474ee04298 (patch)
tree9137dbc1c5d38b2d4e7a3f308ac8ec46081cbd2e
parentc237e9357ba6ee40db59555cfff76bfaa8b5a8a0 (diff)
downloadgcc-564a9fa14ef114c12a4c070a92abf9474ee04298.tar.gz
Cilk Plus <#pragma simd> implementation on top of OMP_SIMD.
-rw-r--r--gcc/ChangeLog.cilkplus47
-rw-r--r--gcc/Makefile.in5
-rw-r--r--gcc/c-family/c-cilkplus.c406
-rw-r--r--gcc/c-family/c-common.h11
-rw-r--r--gcc/c-family/c-pragma.c6
-rw-r--r--gcc/c-family/c-pragma.h14
-rw-r--r--gcc/c/c-parser.c395
-rw-r--r--gcc/c/c-typeck.c7
-rw-r--r--gcc/cp/ChangeLog.cilkplus28
-rw-r--r--gcc/cp/Make-lang.in3
-rw-r--r--gcc/cp/cp-cilkplus.c78
-rw-r--r--gcc/cp/cp-tree.h4
-rw-r--r--gcc/cp/parser.c541
-rw-r--r--gcc/cp/parser.h1
-rw-r--r--gcc/cp/semantics.c7
-rw-r--r--gcc/gimple-pretty-print.c6
-rw-r--r--gcc/gimple.h3
-rw-r--r--gcc/gimplify.c6
-rw-r--r--gcc/omp-low.c55
-rw-r--r--gcc/testsuite/c-c++-common/cilk-plus/PS/body.c33
-rw-r--r--gcc/testsuite/c-c++-common/cilk-plus/PS/clauses1.c76
-rw-r--r--gcc/testsuite/c-c++-common/cilk-plus/PS/clauses2.c18
-rw-r--r--gcc/testsuite/c-c++-common/cilk-plus/PS/clauses3.c39
-rw-r--r--gcc/testsuite/c-c++-common/cilk-plus/PS/for1.c139
-rw-r--r--gcc/testsuite/c-c++-common/cilk-plus/PS/for3.c8
-rw-r--r--gcc/testsuite/c-c++-common/cilk-plus/PS/for4.c14
-rw-r--r--gcc/testsuite/c-c++-common/cilk-plus/PS/for5.c11
-rw-r--r--gcc/testsuite/c-c++-common/cilk-plus/PS/p_simd_test1.c36
-rw-r--r--gcc/testsuite/c-c++-common/cilk-plus/PS/p_simd_test2.c41
-rw-r--r--gcc/testsuite/c-c++-common/cilk-plus/PS/reduction_ex.c36
-rw-r--r--gcc/testsuite/c-c++-common/cilk-plus/PS/run-1.c28
-rw-r--r--gcc/testsuite/c-c++-common/cilk-plus/PS/safelen.c14
-rw-r--r--gcc/testsuite/c-c++-common/cilk-plus/PS/vectorlength.c21
-rw-r--r--gcc/testsuite/g++.dg/cilk-plus/cilk-plus.exp8
-rw-r--r--gcc/testsuite/g++.dg/cilk-plus/for.C12
-rw-r--r--gcc/testsuite/g++.dg/cilk-plus/for2.C26
-rw-r--r--gcc/testsuite/g++.dg/dg.exp1
-rw-r--r--gcc/testsuite/gcc.dg/cilk-plus/auto.c17
-rw-r--r--gcc/testsuite/gcc.dg/cilk-plus/cilk-plus.exp7
-rw-r--r--gcc/testsuite/gcc.dg/cilk-plus/for1.c12
-rw-r--r--gcc/testsuite/gcc.dg/cilk-plus/for2.c66
-rw-r--r--gcc/testsuite/gcc.dg/cilk-plus/jump.c27
-rw-r--r--gcc/tree-pretty-print.c4
-rw-r--r--gcc/tree.def4
-rw-r--r--gcc/tree.h13
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)