@@ -1,3 +1,8 @@
+2013-05-21 Balaji V. Iyer <balaji.v.iyer@intel.com>
+
+testsuite/
+ * g++.dg/cilk-plus: New directory and associated infrastructure.
+
2013-05-13 Aldy Hernandez <aldyh@redhat.com>
* Makefile.in (C_COMMON_OBJS): Depend on c-family/c-cilkplus.o.
new file mode 100755
@@ -0,0 +1,18 @@
+2013-05-21 Balaji V. Iyer <balaji.v.iyer@intel.com>
+
+ * cp-tree.h (p_simd_valid_stmts_in_body_p): New prototype.
+ * 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.
+ * 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.
+
@@ -80,7 +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-gimplify.o $(CXX_C_OBJS)
+ cp/cp-gimplify.o cp/cp-cilkplus.o $(CXX_C_OBJS)
# Language-specific object files for C++.
CXX_OBJS = cp/cp-lang.o c-family/stub-objc.o $(CXX_AND_OBJCXX_OBJS)
@@ -345,3 +345,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)
new file mode 100755
@@ -0,0 +1,98 @@
+/* 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"
+
+
+/* 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
+find_invalid_stmts (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;
+ else if (TREE_CODE (*tp) == GOTO_EXPR)
+ {
+ error_at (loc, "goto statements are not allowed inside "
+ "loops marked with #pragma simd");
+ *valid = false;
+ *walk_subtrees = 0;
+ }
+ else if (TREE_CODE (*tp) == THROW_EXPR)
+ {
+ error_at (loc, "throw expressions are not allowed inside the loop "
+ "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 loop marked with "
+ "#pragma simd");
+ *valid = false;
+ *walk_subtrees = 0;
+ }
+ else if (TREE_CODE (*tp) == 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 (loc, "setjmps are not allowed inside loops marked with"
+ " #pragma simd");
+ *valid = false;
+ *walk_subtrees = 0;
+ }
+ }
+ }
+ /* FIXME: Add a check for TREE_CODE (*tp) == CILK_FOR_STMT and flag them as
+ invalid when cilk keywords are adopted. */
+ 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
+p_simd_valid_stmts_in_body_p (tree body)
+{
+ bool valid = true;
+ cp_walk_tree (&body, find_invalid_stmts, (void *) &valid, NULL);
+ return valid;
+}
old mode 100644
new mode 100755
@@ -6140,6 +6140,9 @@ 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 p_simd_valid_stmts_in_body_p (tree);
+
/* -- end of C++ */
#endif /* ! GCC_CP_TREE_H */
old mode 100644
new mode 100755
@@ -231,6 +231,12 @@ 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
@@ -10297,6 +10303,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 statements are not allowed inside"
+ " <#pragma simd> loop body");
+ break;
}
cp_parser_require (parser, CPP_SEMICOLON, RT_SEMICOLON);
break;
@@ -10314,6 +10324,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 statements are not allowed"
+ " inside <#pragma simd> loop body");
+ break;
default:
gcc_unreachable ();
}
@@ -29458,6 +29472,7 @@ cp_parser_initial_pragma (cp_token *first_token)
cp_lexer_get_preprocessor_token (NULL, first_token);
}
+
/* Normal parsing of a pragma token. Here we can (and must) use the
regular lexer. */
@@ -29605,6 +29620,11 @@ cp_parser_pragma (cp_parser *parser, enum pragma_context context)
"%<#pragma omp sections%> construct");
break;
+ case PRAGMA_CILK_SIMD:
+ if (context == pragma_external)
+ goto bad_stmt;
+ cp_parser_cilk_simd_construct (parser, pragma_tok);
+ return true;
default:
gcc_assert (id >= PRAGMA_FIRST_EXTERNAL);
c_invoke_pragma_handler (id);
@@ -29670,4 +29690,663 @@ 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;
+ /* Vectorlength clause behaves exactly like Open MP 4.0'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 = fold_non_dependent_expr (expr);
+
+ if (!TREE_TYPE (expr) || !TREE_CONSTANT (expr)
+ || TREE_CODE (expr) == VAR_DECL || TREE_CODE (expr) == PARM_DECL
+ || !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 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 = fold_non_dependent_expr (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. value 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, tree *name)
+{
+ pragma_cilk_clause clause_type;
+ cp_token *token = cp_lexer_peek_token (parser->lexer);
+
+ 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), "private"))
+ clause_type = PRAGMA_CILK_CLAUSE_PRIVATE;
+ 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
+ {
+ *name = token->u.value;
+ return PRAGMA_CILK_CLAUSE_NONE;
+ }
+
+ *name = token->u.value;
+ 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;
+ tree name = 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, &name);
+ 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;
+ error_at (cp_lexer_peek_token (parser->lexer)->location,
+ "invalid/unimplemented %<#pragma simd%> clause: %qE",
+ name);
+ 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 loop. */
+
+static void
+cp_parser_cilk_simd_construct (cp_parser *parser, cp_token *pragma_token)
+{
+ tree sb;
+ int save;
+ 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,
+ "expected for-statement after %<#pragma simd%> clauses");
+ return;
+ }
+
+ /* #pragma simd is build on top of OpenMP 4.0's OMP_SIMD treees. Thus
+ openmp must be enabled. */
+ if (!flag_openmp)
+ flag_openmp = true;
+ sb = begin_omp_structured_block ();
+ 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, "for-loop initializer must declare variable");
+ return error_mark_node;
+ }
+ 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);
+ 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;
+ 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
+ {
+ decl = NULL_TREE;
+ 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;
+}
+
+
+/* Parses the increment expresion for a cilk_for or for statement with
+ #pragma simd. */
+
+static tree
+cp_parser_cilk_for_expression_iterator (cp_parser *parser)
+{
+ cp_token *token = cp_lexer_peek_token (parser->lexer);
+ tree name = NULL_TREE, expr = NULL_TREE;
+ enum tree_code t_code = NOP_EXPR;
+
+ if (token->type == CPP_SEMICOLON)
+ {
+ error_at (token->location, "missing loop expression");
+ return error_mark_node;
+ }
+ if (token->type == CPP_PLUS_PLUS || token->type == CPP_MINUS_MINUS)
+ {
+ cp_lexer_consume_token (parser->lexer);
+ token = cp_lexer_peek_token (parser->lexer);
+ t_code = token->type == CPP_PLUS_PLUS ? PREINCREMENT_EXPR
+ : PREDECREMENT_EXPR;
+ }
+
+ if (token->type != CPP_NAME)
+ {
+ error_at (token->location, "invalid loop expression");
+ cp_parser_skip_to_end_of_statement (parser);
+ return error_mark_node;
+ }
+
+ name = cp_parser_lookup_name (parser, token->u.value, none_type, false, false,
+ false, NULL, token->location);
+ if (name == error_mark_node)
+ return error_mark_node;
+
+ /* If name is not a declaration, then the loop is not valid. */
+ if (!DECL_P (name))
+ {
+ error_at (token->location, "invalid loop increment expression");
+ return error_mark_node;
+ }
+ cp_lexer_consume_token (parser->lexer);
+ token = cp_lexer_peek_token (parser->lexer);
+
+ if (t_code != NOP_EXPR)
+ {
+ if (token->type != CPP_CLOSE_PAREN)
+ {
+ error_at (token->location, "invalid loop expression");
+ return error_mark_node;
+ }
+ return build2 (t_code, void_type_node, name, NULL_TREE);
+ }
+
+ if (token->type == CPP_CLOSE_PAREN)
+ {
+ error_at (token->location,
+ "loop expression must modify control variable");
+ return error_mark_node;
+ }
+
+ cp_lexer_consume_token (parser->lexer);
+ if (token->type == CPP_PLUS_PLUS || token->type == CPP_MINUS_MINUS)
+ return build2 (token->type == CPP_PLUS_PLUS ? POSTINCREMENT_EXPR
+ : POSTDECREMENT_EXPR, void_type_node, name, NULL_TREE);
+ else if (token->type == CPP_EQ)
+ {
+ sorry ("loop with = operator");
+ return error_mark_node;
+ }
+ else if (token->type == CPP_PLUS_EQ || token->type == CPP_MINUS_EQ)
+ t_code = token->type == CPP_PLUS_EQ ? PLUS_EXPR : MINUS_EXPR;
+ else if (token->type == CPP_MOD_EQ || token->type == CPP_XOR_EQ
+ || token->type == CPP_DIV_EQ || token->type == CPP_AND_EQ
+ || token->type == CPP_OR_EQ || token->type == CPP_AND_EQ
+ || token->type == CPP_LSHIFT_EQ || token->type == CPP_RSHIFT_EQ)
+ {
+ error_at (token->location, "invalid loop increment operation");
+ return error_mark_node;
+ }
+ else
+ {
+ error_at (token->location, "invalid loop expression");
+ return error_mark_node;
+ }
+ expr = cp_parser_binary_expression (parser, false, false, PREC_NOT_OPERATOR,
+ NULL);
+ if (expr == error_mark_node)
+ return expr;
+
+ return build2 (MODIFY_EXPR, void_type_node, name,
+ build2 (t_code, TREE_TYPE (name), name, expr));
+}
+
+/* Parses the condition for a for-loop with pragma simd or _Cilk_for loop. */
+
+static tree
+cp_parser_cilk_for_condition (cp_parser *parser)
+{
+ tree lhs, rhs;
+ enum tree_code code = ERROR_MARK;
+
+ lhs = cp_parser_binary_expression (parser, false, false,
+ PREC_SHIFT_EXPRESSION, NULL);
+ switch (cp_lexer_peek_token (parser->lexer)->type)
+ {
+ case CPP_NOT_EQ:
+ code = NE_EXPR;
+ break;
+ case CPP_LESS:
+ code = LT_EXPR;
+ break;
+ case CPP_LESS_EQ:
+ code = LE_EXPR;
+ break;
+ case CPP_GREATER_EQ:
+ code = GE_EXPR;
+ break;
+ case CPP_GREATER:
+ code = GT_EXPR;
+ break;
+ case CPP_EQ_EQ:
+ error_at (cp_lexer_peek_token (parser->lexer)->location,
+ "equality test not permitted in the Cilk_for loop");
+ break;
+ default:
+ error_at (cp_lexer_peek_token (parser->lexer)->location,
+ "missing comparison operator in the loop condition");
+ }
+ cp_lexer_consume_token (parser->lexer);
+
+ rhs = cp_parser_binary_expression (parser, false, false,
+ PREC_SHIFT_EXPRESSION, NULL);
+ parser->scope = NULL_TREE;
+ parser->qualifying_scope = NULL_TREE;
+ parser->object_scope = NULL_TREE;
+
+ if (code == ERROR_MARK || lhs == error_mark_node || rhs == error_mark_node)
+ return error_mark_node;
+
+ return build2 (code, boolean_type_node, lhs, rhs);
+}
+
+/* Top-level function to parse _Cilk_for and for statements. */
+
+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;
+
+ /* FIXME: Allow CILK_FOR into this function. That is, use this function to
+ parse _Cilk_for statments also. To do this correctly, add another param.
+ called "grain" to hold the grainsize. */
+
+ 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;
+ }
+
+ 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 (!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, "%s-loop requires a condition",
+ for_keyword == RID_FOR ? "for" : "_Cilk_for");
+ cond = error_mark_node;
+ }
+ else
+ cond = cp_parser_cilk_for_condition (parser);
+
+ if (cond == error_mark_node)
+ valid = false;
+ cp_parser_consume_semicolon_at_end_of_statement (parser);
+
+ if (cp_lexer_next_token_is (parser->lexer, CPP_CLOSE_PAREN))
+ {
+ error_at (loc, "%s-loop requires an increment expression",
+ for_keyword == RID_FOR ? "for" : "_Cilk_for");
+ incr_expr = error_mark_node;
+ }
+ else
+ incr_expr = cp_parser_cilk_for_expression_iterator (parser);
+
+ 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)
+ {
+ tree initv, incrv, condv, declv, omp_simd_node, body = NULL_TREE;
+
+ parser->in_statement = IN_CILK_P_SIMD_FOR;
+ 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 (!p_simd_valid_stmts_in_body_p (body))
+ return error_mark_node;
+
+ /* Now pass all the information into finish_omp_for. */
+ initv = make_tree_vec (1);
+ condv = make_tree_vec (1);
+ incrv = make_tree_vec (1);
+ declv = make_tree_vec (1);
+ TREE_VEC_ELT (initv, 0) = init;
+ TREE_VEC_ELT (condv, 0) = cond;
+ TREE_VEC_ELT (incrv, 0) = incr_expr;
+ TREE_VEC_ELT (declv, 0) = decl;
+ omp_simd_node = finish_omp_for (loc, OMP_SIMD, declv, initv, condv, incrv,
+ body, pre_body, clauses);
+ return omp_simd_node;
+ }
+ else
+ /* Fix this when _Cilk_for is added into the mix. */
+ return NULL_TREE;
+}
+
#include "gt-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.
new file mode 100644
@@ -0,0 +1,23 @@
+# Copyright (C) 2013 Free Software Foundation, Inc.
+
+# This program 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 of the License, or
+# (at your option) any later version.
+#
+# This program 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/>.
+
+load_lib gcc-dg.exp
+
+set OPTS "-fcilkplus -c -ftree-vectorize"
+
+dg-init
+dg-runtest [lsort [glob -nocomplain $srcdir/$subdir/*.cc]] " $OPTS" " "
+dg-finish
new file mode 100644
@@ -0,0 +1,62 @@
+/* { dg-do compile } */
+/* { dg-options "-O3 -fcilkplus" } */
+
+#include <setjmp.h>
+int main(void)
+{
+ int q = 0;
+#pragma simd
+ for (int ii = 0; ii < 1000; ii++)
+ break; /* { dg-error "break statements are not allowed" } */
+
+#pragma simd linear (q)
+ for (int ii = 0; ii < 1000; ii++) {
+ if (q)
+ continue; /* { dg-error "continue statements are not allowed" } */
+ }
+#pragma simd
+ for (int ii = 0; ii < 1000; ii++)
+ {
+L5:
+ goto L5; /* { dg-error "goto statements are not allowed" } */
+ }
+
+#pragma simd
+ for (int ii = 0; ii < 1000; ii++)
+ {
+ try { /* { dg-error "try statements are not allowed" } */
+ ii = ii %2;
+ }
+ catch (...)
+ {
+ }
+ }
+
+#pragma simd
+ for (int ii = 0; ii < 1000; ii++)
+ {
+ while (ii % 2) {
+ ii++;
+ throw; /* { dg-error "throw expressions are not allowed" } */
+ }
+ }
+
+#pragma simd
+ for (int ii = 0; ii < 1000; ii++)
+ {
+ jmp_buf x;
+ if (!setjmp (x)) /* { dg-error "setjmps are not allowed inside" } */
+ ii++;
+ }
+
+ for (int ii = 0; ii < 1000; ii++)
+ {
+ try { /* This is OK! */
+ ii = ii %2;
+ }
+ catch (...)
+ {
+ }
+ }
+ return 5;
+}
new file mode 100644
@@ -0,0 +1,58 @@
+/* { dg-do compile } */
+/* { dg-options "-fcilkplus" } */
+
+int main (void)
+{
+ int x[10];
+ int z = 0;
+#pragma simd something /* { dg-error "invalid/unimplemented" } */
+ for (int ii = 0; ii < 10; ii++) {
+ x[ii] = 5;
+ }
+ int q = 0;
+#pragma simd
+ while (q < 5) { /* { dg-error "expected for-statement after" } */
+ x[q] = 5;
+ q++;
+ }
+#pragma simd
+ for (int ii; ii < 10; ii++) { /* { dg-error "expected '=' before" } */
+
+ x[q] = 5;
+ }
+
+ int iii = 0;
+#pragma simd
+ for (iii; iii < 10; iii++) { /* { dg-error "for-loop initializer does not declare" } */
+ x[iii] = 5;
+ }
+#pragma simd
+ for (; iii < 10; iii++) { /* { dg-error "for-loop initializer must declare" } */
+ x[iii] = 5;
+ }
+
+#pragma simd
+ for (int ii = 0; ii < 10; ) /* { dg-error "for-loop requires an increment expression" } */
+ x[q] = 5;
+
+#pragma simd
+ for (int ii = 0, int jj = 0; ii < 10; ii++ ) /* { dg-error "for-loop initializer cannot have multiple" } */
+ x[q] = 5;
+
+#pragma simd
+ for (int ii = 0; ii == 10; ii++) /* { dg-error "equality test not permitted" } */
+ x[q] = 5;
+
+#pragma simd
+ for (int ii = 0; ii < 10; ii++,jj++) /* { dg-error "expected '\\)' before" } */
+ x[q] = 5;
+
+#pragma simd /* This is OK! */
+ for (int ii = 0; ii < 10; ii++) {
+ x[ii] = 5;
+ }
+
+ return x[9];
+}
+
new file mode 100644
@@ -0,0 +1,64 @@
+/* { dg-do compile } */
+/* { dg-options "-fcilkplus" } */
+
+template <class TPLT>
+TPLT main2 (int argc, char **argv)
+{
+ TPLT x[10];
+ TPLT z = 0;
+
+#pragma simd something /* { dg-error "invalid/unimplemented" } */
+ for (TPLT ii = 0; ii < 10; ii++) {
+ x[ii] = 5;
+ }
+ TPLT q = 0;
+#pragma simd
+ while (q < 5) { /* { dg-error "expected for-statement after" } */
+ x[q] = 5;
+ q++;
+ }
+#pragma simd
+ for (TPLT ii; ii < 10; ii++) { /* { dg-error "expected" } */
+ x[q] = 5;
+ }
+
+ TPLT iii = 0;
+#pragma simd
+ for (iii; iii < 10; iii++) { /* { dg-error "for-loop initializer does not declare" } */
+ x[iii] = 5;
+ }
+#pragma simd
+ for (; iii < 10; iii++) { /* { dg-error "for-loop initializer must declare" } */
+ x[iii] = 5;
+ }
+
+#pragma simd
+ for (TPLT ii = 0; ii < 10; ) /* { dg-error "for-loop requires an increment expression" } */
+ x[q] = 5;
+
+#pragma simd
+ for (TPLT ii = 0, TPLT jj = 0; ii < 10; ii++ ) /* { dg-error "for-loop initializer cannot have multiple" } */
+ x[q] = 5;
+
+#pragma simd
+ for (TPLT ii = 0; ii == 10; ii++) /* { dg-error "equality test not permitted" } */
+ x[q] = 5;
+
+#pragma simd
+ for (TPLT ii = 0; ii != 10; ii++,jj++) /* { dg-error "expected" } */
+ x[q] = 5;
+
+#pragma simd /* This is OK! */
+ for (TPLT ii = 0; ii < 10; ii++) {
+ x[ii] = 5;
+ }
+ return x[9];
+}
+
+int main (int argc, char **argv)
+{
+ main2 <int> (argc, argv);
+ return 0;
+}
+
new file mode 100644
@@ -0,0 +1,61 @@
+/* { dg-do compile } */
+/* { dg-options "-fcilkplus" } */
+
+int main (void)
+{
+ int x[10];
+ int z = 0, y = 5;
+
+#pragma simd linear (5) /* { dg-error "expected identifier before" } */
+ for (int ii = 0; ii < 10; ii++) {
+ x[ii] = z;
+ }
+
+#pragma simd linear (:5) /* { dg-error "expected identifier before" } */
+ for (int ii = 0; ii < 10; ii++) {
+ x[ii] = z;
+ }
+
+#pragma simd linear (z:) /* { dg-error "expected primary-expression before" } */
+ for (int ii = 0; ii < 10; ii++) {
+ x[ii] = z;
+ }
+
+#pragma simd linear (z) /* This is OK! */
+ for (int ii = 0; ii < 10; ii++) {
+ x[ii] = z;
+ }
+
+#pragma simd linear (x, z) /* This is OK! */
+ for (int ii = 0; ii < 10; ii++) {
+ x[ii] = z;
+ }
+
+#pragma simd linear (x:1, z) /* This is OK! */
+ for (int ii = 0; ii < 10; ii++) {
+ x[ii] = z;
+ }
+
+#pragma simd linear (y, x:1, z:2) /* This is OK! */
+ for (int ii = 0; ii < 10; ii++) {
+ x[ii] = y + z;
+ }
+
+#pragma simd linear (q) /* { dg-error "has not been declared" } */
+ for (int ii = 0; ii < 10; ii++) {
+ x[ii] = z;
+ }
+
+#pragma simd linear (y, :5) /* { dg-error "expected variable-name" } */
+ for (int ii = 0; ii < 10; ii++) {
+ x[ii] = (z + y);
+ }
+
+#pragma simd linear (y,5) /* { dg-error "expected variable-name before numeric" } */
+ for (int ii = 0; ii < 10; ii++) {
+ x[ii] = (z + y);
+ }
+ return x[9];
+}
+
new file mode 100644
@@ -0,0 +1,41 @@
+/* { dg-do compile } */
+/* { dg-options "-fcilkplus" } */
+
+int main (void)
+{
+ int x[10];
+ int z = 0;
+ const int zz = 0;
+#pragma simd vectorlength (4, 8) /* { dg-error "expected" } */
+ for (int ii = 0; ii < 10; ii++) {
+ x[ii] = 5;
+ }
+#pragma simd vectorlength (5) /* { dg-error "vectorlength must be a power" } */
+ for (int ii = 0; ii < 10; ii++) {
+ x[ii] = 5;
+ }
+
+#pragma simd vectorlength (5.2) /* { dg-error "vectorlength must be an integer" } */
+ for (int ii = 0; ii < 10; ii++) {
+ x[ii] = 5;
+ }
+
+#pragma simd vectorlength (zz) /* { dg-error "vectorlength must be an integer" } */
+ for (int ii = 0; ii < 10; ii++) {
+ x[ii] = 5;
+ }
+
+#pragma simd vectorlength 4 /* { dg-error "before numeric" } */
+ for (int ii = 0; ii < 10; ii++) {
+ x[ii] = 5;
+ }
+
+#pragma simd vectorlength (4 /* { dg-error "before end of" } */
+ for (int ii = 0; ii < 10; ii++) {
+ x[ii] = 5;
+ }
+
+ return x[9];
+}
+