From patchwork Tue May 21 15:46:16 2013 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: "Iyer, Balaji V" X-Patchwork-Id: 245334 Return-Path: X-Original-To: incoming@patchwork.ozlabs.org Delivered-To: patchwork-incoming@bilbo.ozlabs.org Received: from sourceware.org (server1.sourceware.org [209.132.180.131]) (using TLSv1 with cipher DHE-RSA-AES256-SHA (256/256 bits)) (Client CN "localhost", Issuer "www.qmailtoaster.com" (not verified)) by ozlabs.org (Postfix) with ESMTPS id A68732C00A4 for ; Wed, 22 May 2013 01:47:03 +1000 (EST) DomainKey-Signature: a=rsa-sha1; c=nofws; d=gcc.gnu.org; h=list-id :list-unsubscribe:list-archive:list-post:list-help:sender:from :to:cc:subject:date:message-id:content-type:mime-version; q=dns; s=default; b=AtKIdeA6ofLZMSQDYLn116nNDcPBGCF8vy0AqdV3/l5GxjENYV oG6Wm3vfqgLSCpbWq8DHHhUec/ElToqD3Y3XUmvM3pCuTWMkggZeFxdDxns31p9S quBE3v+vbuojLMq0HDJbmMFsWYwol78C3AjSLhMzisxylBLtUuFnhV61k= DKIM-Signature: v=1; a=rsa-sha1; c=relaxed; d=gcc.gnu.org; h=list-id :list-unsubscribe:list-archive:list-post:list-help:sender:from :to:cc:subject:date:message-id:content-type:mime-version; s= default; bh=sae8WCc8Z2dMblx5JySU+Qu1IFg=; b=Z7bH9+yHTEuWlMwnvbGM 55MLqDbSLq6rdsKemMArVoeO+g21M10u2uJIzAR3suxrTBeI77h0noVukMS5x8gI nBfy/3gmfofKBD87cNm47fAAIKgFIq4H+mAcwlN1q0/zXOmduDFWoza0uCW4BnJL ipji8nEaiWXVffoZf4oNg9Q= Received: (qmail 13530 invoked by alias); 21 May 2013 15:46:25 -0000 Mailing-List: contact gcc-patches-help@gcc.gnu.org; run by ezmlm Precedence: bulk List-Id: List-Unsubscribe: List-Archive: List-Post: List-Help: Sender: gcc-patches-owner@gcc.gnu.org Delivered-To: mailing list gcc-patches@gcc.gnu.org Received: (qmail 13476 invoked by uid 89); 21 May 2013 15:46:24 -0000 X-Spam-SWARE-Status: No, score=-7.0 required=5.0 tests=AWL, BAYES_00, RCVD_IN_HOSTKARMA_W, RCVD_IN_HOSTKARMA_WL, RP_MATCHES_RCVD, SPF_PASS, TW_BJ, TW_FN, TW_JC, TW_TJ, TW_TM autolearn=ham version=3.3.1 Received: from mga02.intel.com (HELO mga02.intel.com) (134.134.136.20) by sourceware.org (qpsmtpd/0.84/v0.84-167-ge50287c) with ESMTP; Tue, 21 May 2013 15:46:21 +0000 Received: from fmsmga001.fm.intel.com ([10.253.24.23]) by orsmga101.jf.intel.com with ESMTP; 21 May 2013 08:46:18 -0700 X-ExtLoop1: 1 Received: from fmsmsx103.amr.corp.intel.com ([10.19.9.34]) by fmsmga001.fm.intel.com with ESMTP; 21 May 2013 08:46:20 -0700 Received: from fmsmsx114.amr.corp.intel.com (10.18.116.8) by FMSMSX103.amr.corp.intel.com (10.19.9.34) with Microsoft SMTP Server (TLS) id 14.3.123.3; Tue, 21 May 2013 08:46:17 -0700 Received: from fmsmsx101.amr.corp.intel.com ([169.254.1.135]) by FMSMSX114.amr.corp.intel.com ([169.254.6.129]) with mapi id 14.03.0123.003; Tue, 21 May 2013 08:46:16 -0700 From: "Iyer, Balaji V" To: "Aldy Hernandez (aldyh@redhat.com)" CC: "gcc-patches@gcc.gnu.org" , Jakub Jelinek Subject: [gomp4/cilk-in-gomp/cilkplus] C++ parsing for Cilk plus <#pragma simd> Date: Tue, 21 May 2013 15:46:16 +0000 Message-ID: MIME-Version: 1.0 X-Virus-Found: No Hello Aldy et al., Attached, please find a patch on top of gomp4 branch that implements Cilk's <#pragma simd> for C++. This is done in the same fashion as Aldy did in: http://gcc.gnu.org/ml/gcc-patches/2013-05/msg00678.html (It creates OMP_SIMD trees and let omp-low do the rest). This patch should be applied on Aldy's branch aldyh/cilk-in-gomp. I have also included testsuite code that will catch several errors. Aldy, is this OK for your branch? Thanks, Balaji V. Iyer. diff --git gcc/ChangeLog.cilkplus gcc/ChangeLog.cilkplus index 5e9fb79..8a7ed94 100644 --- gcc/ChangeLog.cilkplus +++ gcc/ChangeLog.cilkplus @@ -1,3 +1,8 @@ +2013-05-21 Balaji V. Iyer + +testsuite/ + * g++.dg/cilk-plus: New directory and associated infrastructure. + 2013-05-13 Aldy Hernandez * Makefile.in (C_COMMON_OBJS): Depend on c-family/c-cilkplus.o. diff --git gcc/cp/ChangeLog.cilkplus gcc/cp/ChangeLog.cilkplus new file mode 100755 index 0000000..7254b81 --- /dev/null +++ gcc/cp/ChangeLog.cilkplus @@ -0,0 +1,18 @@ +2013-05-21 Balaji V. Iyer + + * 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. + diff --git gcc/cp/Make-lang.in gcc/cp/Make-lang.in index cda4897..55ed6d4 100644 --- gcc/cp/Make-lang.in +++ gcc/cp/Make-lang.in @@ -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) diff --git gcc/cp/cp-cilkplus.c gcc/cp/cp-cilkplus.c new file mode 100755 index 0000000..118fd58 --- /dev/null +++ gcc/cp/cp-cilkplus.c @@ -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 , + Aldy Hernandez . + + 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 + . */ + +#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; +} diff --git gcc/cp/cp-tree.h gcc/cp/cp-tree.h old mode 100644 new mode 100755 index 1e2230b..7c0cfeb --- gcc/cp/cp-tree.h +++ gcc/cp/cp-tree.h @@ -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 */ diff --git gcc/cp/parser.c gcc/cp/parser.c old mode 100644 new mode 100755 index 8882a83..1dba40f --- gcc/cp/parser.c +++ gcc/cp/parser.c @@ -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" diff --git gcc/cp/parser.h gcc/cp/parser.h index 6d9f1fb..48ec8dd 100644 --- gcc/cp/parser.h +++ 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 gcc/testsuite/g++.dg/cilk-plus/errors/cilkplus_CPP_PS_errors.exp gcc/testsuite/g++.dg/cilk-plus/errors/cilkplus_CPP_PS_errors.exp new file mode 100644 index 0000000..1f8ace8 --- /dev/null +++ gcc/testsuite/g++.dg/cilk-plus/errors/cilkplus_CPP_PS_errors.exp @@ -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 +# . + +load_lib gcc-dg.exp + +set OPTS "-fcilkplus -c -ftree-vectorize" + +dg-init +dg-runtest [lsort [glob -nocomplain $srcdir/$subdir/*.cc]] " $OPTS" " " +dg-finish diff --git gcc/testsuite/g++.dg/cilk-plus/errors/for_body_errors.cc gcc/testsuite/g++.dg/cilk-plus/errors/for_body_errors.cc new file mode 100644 index 0000000..797cb89 --- /dev/null +++ gcc/testsuite/g++.dg/cilk-plus/errors/for_body_errors.cc @@ -0,0 +1,62 @@ +/* { dg-do compile } */ +/* { dg-options "-O3 -fcilkplus" } */ + +#include +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; +} diff --git gcc/testsuite/g++.dg/cilk-plus/errors/general_errors.cc gcc/testsuite/g++.dg/cilk-plus/errors/general_errors.cc new file mode 100644 index 0000000..b9a2711 --- /dev/null +++ gcc/testsuite/g++.dg/cilk-plus/errors/general_errors.cc @@ -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]; +} + diff --git gcc/testsuite/g++.dg/cilk-plus/errors/general_errors_tplt.cc gcc/testsuite/g++.dg/cilk-plus/errors/general_errors_tplt.cc new file mode 100644 index 0000000..7b8859b --- /dev/null +++ gcc/testsuite/g++.dg/cilk-plus/errors/general_errors_tplt.cc @@ -0,0 +1,64 @@ +/* { dg-do compile } */ +/* { dg-options "-fcilkplus" } */ + +template +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 (argc, argv); + return 0; +} + diff --git gcc/testsuite/g++.dg/cilk-plus/errors/linear_error.cc gcc/testsuite/g++.dg/cilk-plus/errors/linear_error.cc new file mode 100644 index 0000000..addabdf --- /dev/null +++ gcc/testsuite/g++.dg/cilk-plus/errors/linear_error.cc @@ -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]; +} + diff --git gcc/testsuite/g++.dg/cilk-plus/errors/vlength_error.cc gcc/testsuite/g++.dg/cilk-plus/errors/vlength_error.cc new file mode 100644 index 0000000..3de33c5 --- /dev/null +++ gcc/testsuite/g++.dg/cilk-plus/errors/vlength_error.cc @@ -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]; +} +