From patchwork Tue Aug 27 20:03:26 2013 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: Aldy Hernandez X-Patchwork-Id: 270213 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 "www.sourceware.org", Issuer "StartCom Class 1 Primary Intermediate Server CA" (not verified)) by ozlabs.org (Postfix) with ESMTPS id A7F5B2C00E7 for ; Wed, 28 Aug 2013 06:03:51 +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 :message-id:date:from:mime-version:to:cc:subject:references :in-reply-to:content-type; q=dns; s=default; b=CX4FXgi/rauh/akcp DntcBpFaacz7uOufU05qLltIf4QaBr0OqXsOUDb3EP5aYPXhN+otGXG/QOijrka1 vt6jry2exLk9oYetk4iSq8Dx10l38fAMPr6FL38P5qOuCn97DepItvV1CvjiDfZW faA2xRFG1JUSpRyWKncWKbSoac= 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 :message-id:date:from:mime-version:to:cc:subject:references :in-reply-to:content-type; s=default; bh=l3jM3GzEnlYgVwxpv8MlStq exf8=; b=npST1bHF6SwisixzXuceC8nu5aZ0Fnlt3JkhQPxdjVKtX+/dNPG+wQ5 M8qwKcoBjpgOhhZ/r+g1vGulAIdTKuOlp5p7/iLWE/bu7jc8zrHR0+/V9a7hewzD hSF2hyQu3z8eXvgB+gfY8h+oUrvSIn27UU1eZoxw1+H5UknQNBJY= Received: (qmail 5998 invoked by alias); 27 Aug 2013 20:03:40 -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 5935 invoked by uid 89); 27 Aug 2013 20:03:40 -0000 Received: from mx1.redhat.com (HELO mx1.redhat.com) (209.132.183.28) by sourceware.org (qpsmtpd/0.93/v0.84-503-g423c35a) with ESMTP; Tue, 27 Aug 2013 20:03:40 +0000 Authentication-Results: sourceware.org; auth=none X-Virus-Found: No X-Spam-SWARE-Status: No, score=-5.9 required=5.0 tests=BAYES_00, KHOP_THREADED, RP_MATCHES_RCVD autolearn=ham version=3.3.2 X-HELO: mx1.redhat.com Received: from int-mx11.intmail.prod.int.phx2.redhat.com (int-mx11.intmail.prod.int.phx2.redhat.com [10.5.11.24]) by mx1.redhat.com (8.14.4/8.14.4) with ESMTP id r7RK3SDt009892 (version=TLSv1/SSLv3 cipher=DHE-RSA-AES256-SHA bits=256 verify=OK) for ; Tue, 27 Aug 2013 16:03:29 -0400 Received: from houston.quesejoda.com (vpn-56-29.rdu2.redhat.com [10.10.56.29]) by int-mx11.intmail.prod.int.phx2.redhat.com (8.14.4/8.14.4) with ESMTP id r7RK3Q1V032358; Tue, 27 Aug 2013 16:03:26 -0400 Message-ID: <521D060E.9030601@redhat.com> Date: Tue, 27 Aug 2013 15:03:26 -0500 From: Aldy Hernandez User-Agent: Mozilla/5.0 (X11; Linux x86_64; rv:17.0) Gecko/20130625 Thunderbird/17.0.7 MIME-Version: 1.0 To: Richard Henderson CC: jason merrill , gcc-patches Subject: Re: PING: Fwd: Re: [patch] implement Cilk Plus simd loops on trunk References: <51F299D3.5020907@redhat.com> <521269E0.1020104@redhat.com> <521B8ECA.70806@redhat.com> In-Reply-To: <521B8ECA.70806@redhat.com> On 08/26/13 12:22, Richard Henderson wrote: >> +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; >> + } > > Either these tests are swapped, or the second one isn't really needed. Swapped. Fixed. > > >> + 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; > > Handling pointer types and pointer_plus_expr here (p++) ... > >> + 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; > > ... but not here (p += 1)? I should make the code more obvious. What I'm trying to do is generate what the gimplifier for OMP_FOR is expecting. OMP rewrites pointer increment/decrement expressions into a corresponding MODIFY_EXPR. I have abstracted the OMP code and shared it between both type checks, and I have also added an assert in the gimplifier just in case some future front-end extension generates OMP_FOR_INCR in a wonky way. > > >> +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; > > Why bother checking for setjmp? While I agree it makes little sense, there are > plenty of other standard functions which also make no sense to use from within > #pragma simd. What's likely to go wrong with a call to setjmp, as opposed to > getcontext, pthread_create, or even printf? Sigh...the standard specifically disallows setjmp. > >> + if (DECL_REGISTER (decl)) >> + { >> + error_at (loc, "induction variable cannot be declared register"); >> + return false; >> + } > > Why? The standard :(. > > All of the actual gimple changes look good. You could commit those now if you > like to reduce the size of the next patch. Ughh...got lazy on this round. How about I commit the gimple changes for the next round? How does this look? --- a/gcc/ChangeLog +++ b/gcc/ChangeLog @@ -1,3 +1,28 @@ +2013-08-27 Aldy Hernandez + Balaji V. Iyer + + * 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. + 2013-08-27 Jakub Jelinek Aldy Hernandez --- a/gcc/c-family/ChangeLog +++ b/gcc/c-family/ChangeLog @@ -1,3 +1,17 @@ +2013-08-27 Aldy Hernandez + Balaji V. Iyer + + * 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_omp_for_incr_canonicalize_ptr): Protoize. + * c-omp.c (c_omp_for_incr_canonicalize_ptr): New. + (c_finish_omp_for): ...use it. + 2013-08-26 Gabriel Dos Reis * c-pretty-print.h (c_pretty_printer::unary_expression): Now a --- a/gcc/c/ChangeLog +++ b/gcc/c/ChangeLog @@ -1,3 +1,16 @@ +2013-08-27 Aldy Hernandez + Balaji V. Iyer + + * 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. + 2013-08-26 Joern Rennecke Joseph Myers --- a/gcc/cp/ChangeLog +++ b/gcc/cp/ChangeLog @@ -1,3 +1,28 @@ +2013-08-27 Aldy Hernandez + Balaji V. Iyer + + * cp-gimplify.c (cp_gimplify_expr): Add case for CILK_SIMD. + (cp_genericize_r): Same. + * 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. + (cp_parser_omp_for_cond): Abstract initialization code... + (cp_parser_omp_for_loop_init): ...here. New function. + 2013-08-27 Jakub Jelinek Aldy Hernandez --- a/gcc/testsuite/ChangeLog +++ b/gcc/testsuite/ChangeLog @@ -1,3 +1,8 @@ +2013-08-27 Aldy Hernandez + Balaji V. Iyer + + * gcc.dg/cilk-plus: New directory and associated infrastructure. + 2013-08-27 Vidya Praveen * gcc.target/aarch64/scalar_shift_1.c: New. commit c43d908162e33abeaa3a05e5e15880bd7723a9a9 Author: Aldy Hernandez Date: Fri Jul 5 15:08:07 2013 -0700 Cilk Plus <#pragma simd> implementation on top of OMP_SIMD. diff --git a/gcc/Makefile.in b/gcc/Makefile.in index 387b60f..ef55042 100644 --- a/gcc/Makefile.in +++ b/gcc/Makefile.in @@ -1154,7 +1154,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 @@ -1986,6 +1986,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 0000000..17faec1 --- /dev/null +++ b/gcc/c-family/c-cilkplus.c @@ -0,0 +1,403 @@ +/* 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 , + 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 "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 (!incr) + { + error_at (loc, "missing increment"); + return error_mark_node; + } + + if (EXPR_HAS_LOCATION (incr)) + loc = EXPR_LOCATION (incr); + + switch (TREE_CODE (incr)) + { + case POSTINCREMENT_EXPR: + case PREINCREMENT_EXPR: + case POSTDECREMENT_EXPR: + case PREDECREMENT_EXPR: + if (TREE_OPERAND (incr, 0) != decl) + break; + + return c_omp_for_incr_canonicalize_ptr (loc, decl, 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. + SCAN_BODY is true if the body must be checked. */ + +static bool +c_check_cilk_loop (location_t loc, tree decl, tree cond, tree *incrp, + tree body, bool scan_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, "induction variable must be of integral " + "or pointer type (have %qT)", TREE_TYPE (decl)); + 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 EXPR + EXPR 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 (scan_body && !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 # + 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. + SCAN_BODY is true if the body of the loop must be verified. + + 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, + bool scan_body) +{ + location_t rhs_loc; + + if (!c_check_cilk_loop (loc, decl, cond, &incr, body, scan_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 = build2 (INIT_EXPR, TREE_TYPE (decl), decl, init); + DECL_INITIAL (decl) = NULL; + } + + // The C++ parser just gives us the rhs. + if (TREE_CODE (init) != MODIFY_EXPR) + init = build2 (INIT_EXPR, TREE_TYPE (decl), 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), + "other 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 cc09dbc..3f17d59 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, bool); +extern tree c_finish_cilk_clauses (tree); + /* Language-specific hooks. */ /* If non-NULL, this function is called after a precompile header file @@ -1044,6 +1049,7 @@ extern void c_finish_omp_flush (location_t); extern void c_finish_omp_taskwait (location_t); extern void c_finish_omp_taskyield (location_t); extern tree c_finish_omp_for (location_t, tree, tree, tree, tree, tree, tree); +extern tree c_omp_for_incr_canonicalize_ptr (location_t, tree, tree); extern void c_split_parallel_clauses (location_t, tree, tree *, tree *); extern enum omp_clause_default_kind c_omp_predetermined_sharing (tree); @@ -1137,6 +1143,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, bool); +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-omp.c b/gcc/c-family/c-omp.c index f05b60a..47c9969 100644 --- a/gcc/c-family/c-omp.c +++ b/gcc/c-family/c-omp.c @@ -331,6 +331,28 @@ check_omp_for_incr_expr (location_t loc, tree exp, tree decl) return error_mark_node; } +/* If the OMP_FOR increment expression in INCR is of pointer type, + canonicalize it into an expression handled by gimplify_omp_for() + and return it. DECL is the iteration variable. */ + +tree +c_omp_for_incr_canonicalize_ptr (location_t loc, tree decl, tree incr) +{ + 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; +} + /* Validate and emit code for the OpenMP directive #pragma omp for. DECLV is a vector of iteration variables, for each collapsed loop. INITV, CONDV and INCRV are vectors containing initialization @@ -505,18 +527,7 @@ c_finish_omp_for (location_t locus, tree declv, tree initv, tree condv, break; incr_ok = true; - if (POINTER_TYPE_P (TREE_TYPE (decl)) - && TREE_OPERAND (incr, 1)) - { - tree t = fold_convert_loc (elocus, - sizetype, TREE_OPERAND (incr, 1)); - - if (TREE_CODE (incr) == POSTDECREMENT_EXPR - || TREE_CODE (incr) == PREDECREMENT_EXPR) - t = fold_build1_loc (elocus, NEGATE_EXPR, sizetype, t); - t = fold_build_pointer_plus (decl, t); - incr = build2 (MODIFY_EXPR, void_type_node, decl, t); - } + incr = c_omp_for_incr_canonicalize_ptr (elocus, decl, incr); break; case MODIFY_EXPR: diff --git a/gcc/c-family/c-pragma.c b/gcc/c-family/c-pragma.c index 309859f..428ecfa 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 41215db..4c88dc3 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 b612e29..26c84bc 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). @@ -8952,6 +8956,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) { @@ -10984,7 +10995,392 @@ 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 # 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 induction variable 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, + /*scan_body=*/true); + } + + 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 8b3e3d9..209f361 100644 --- a/gcc/c/c-typeck.c +++ b/gcc/c/c-typeck.c @@ -9167,6 +9167,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 body"); + return NULL_TREE; + default: gcc_unreachable (); } diff --git a/gcc/cp/Make-lang.in b/gcc/cp/Make-lang.in index 2c1774f..7bf0634 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 cp/lambda.o \ cp/vtable-class-hierarchy.o $(CXX_C_OBJS) @@ -354,3 +355,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 0000000..ef3bbef --- /dev/null +++ b/gcc/cp/cp-cilkplus.c @@ -0,0 +1,81 @@ +/* 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" + + +/* 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; + + // Validate the C common bits. + c_validate_cilk_plus_loop (tp, walk_subtrees, data); + + 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 876a72a..a00a8fa 100644 --- a/gcc/cp/cp-tree.h +++ b/gcc/cp/cp-tree.h @@ -6153,6 +6153,10 @@ extern void vtv_save_class_info (tree); extern void vtv_recover_class_info (void); extern void vtv_build_vtable_verify_fndecl (void); +/* 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 923277b..3726c60 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 @@ -10370,6 +10375,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; @@ -10387,6 +10396,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 body"); + break; default: gcc_unreachable (); } @@ -27528,6 +27541,191 @@ cp_parser_omp_for_incr (cp_parser *parser, tree decl) return build2 (MODIFY_EXPR, TREE_TYPE (decl), decl, rhs); } +/* Parse the initialization statement of the restricted form of the + for statement allowed by OpenMP and Cilk Plus. + + If parsing for OpenMP, PARSING_OPENMP is true. + + A statement list with possible statements to be prepended to the + for loop is returned in *THIS_PRE_BODYP. + + Upon return, *INITP will contain the initialization expression, + *DECLP will contain the variable declared in the for-init, if any. + *REAL_DECL_P will contain the induction variable. */ + +static bool +cp_parser_omp_for_loop_init (cp_parser *parser, + bool parsing_openmp, + tree *this_pre_bodyp, + vec *for_block, + tree *initp, + tree *declp, + tree *real_declp) +{ + *initp = *declp = *real_declp = NULL; + *this_pre_bodyp = push_stmt_list (); + if (cp_lexer_next_token_is (parser->lexer, CPP_SEMICOLON)) + return false; + + /* See 2.5.1 (in OpenMP 3.0, similar wording is in the 2.5 standard too): + + init-expr: + var = lb + integer-type var = lb + random-access-iterator-type var = lb + pointer-type var = lb + */ + bool add_private_clause = false; + cp_decl_specifier_seq type_specifiers; + + /* First, try to parse as an initialized declaration. See + cp_parser_condition, from whence the bulk of this is copied. */ + + cp_parser_parse_tentatively (parser); + cp_parser_type_specifier_seq (parser, /*is_declaration=*/true, + /*is_trailing_return=*/false, + &type_specifiers); + if (cp_parser_parse_definitely (parser)) + { + /* If parsing a type specifier seq succeeded, then this + MUST be a initialized declaration. */ + tree asm_specification, attributes; + cp_declarator *declarator; + + declarator = cp_parser_declarator (parser, + CP_PARSER_DECLARATOR_NAMED, + /*ctor_dtor_or_conv_p=*/NULL, + /*parenthesized_p=*/NULL, + /*member_p=*/false); + attributes = cp_parser_attributes_opt (parser); + asm_specification = cp_parser_asm_specification_opt (parser); + + if (declarator == cp_error_declarator) + cp_parser_skip_to_end_of_statement (parser); + + else + { + tree pushed_scope, auto_node; + + *declp = start_decl (declarator, &type_specifiers, + SD_INITIALIZED, attributes, + /*prefix_attributes=*/NULL_TREE, + &pushed_scope); + + auto_node = type_uses_auto (TREE_TYPE (*declp)); + if (cp_lexer_next_token_is_not (parser->lexer, CPP_EQ)) + { + if (cp_lexer_next_token_is (parser->lexer, + CPP_OPEN_PAREN)) + { + if (parsing_openmp) + error ("parenthesized initialization is not allowed in " + "OpenMP % loop"); + else + error ("parenthesized initialization is " + "not allowed in for-loop"); + } + else + /* Trigger an error. */ + cp_parser_require (parser, CPP_EQ, RT_EQ); + + *initp = error_mark_node; + cp_parser_skip_to_end_of_statement (parser); + } + else if (CLASS_TYPE_P (TREE_TYPE (*declp)) + || type_dependent_expression_p (*declp) + || auto_node) + { + bool is_direct_init, is_non_constant_init; + + *initp = cp_parser_initializer (parser, + &is_direct_init, + &is_non_constant_init); + + if (auto_node) + { + TREE_TYPE (*declp) + = do_auto_deduction (TREE_TYPE (*declp), *initp, + auto_node); + + if (!CLASS_TYPE_P (TREE_TYPE (*declp)) + && !type_dependent_expression_p (*declp)) + goto non_class; + } + + cp_finish_decl (*declp, *initp, !is_non_constant_init, + asm_specification, + LOOKUP_ONLYCONVERTING); + if (CLASS_TYPE_P (TREE_TYPE (*declp))) + { + if (for_block) + vec_safe_push (for_block, *this_pre_bodyp); + *initp = NULL_TREE; + } + else + *initp = pop_stmt_list (*this_pre_bodyp); + *this_pre_bodyp = NULL_TREE; + } + else + { + /* Consume '='. */ + cp_lexer_consume_token (parser->lexer); + *initp = cp_parser_assignment_expression (parser, false, NULL); + + non_class: + if (TREE_CODE (TREE_TYPE (*declp)) == REFERENCE_TYPE) + *initp = error_mark_node; + else + cp_finish_decl (*declp, NULL_TREE, + /*init_const_expr_p=*/false, + asm_specification, + LOOKUP_ONLYCONVERTING); + } + + if (pushed_scope) + pop_scope (pushed_scope); + } + } + else + { + cp_id_kind idk; + /* If parsing a type specifier sequence failed, then + this MUST be a simple expression. */ + cp_parser_parse_tentatively (parser); + *declp = cp_parser_primary_expression (parser, false, false, + false, &idk); + if (!cp_parser_error_occurred (parser) + && *declp + && DECL_P (*declp) + && CLASS_TYPE_P (TREE_TYPE (*declp))) + { + tree rhs; + + cp_parser_parse_definitely (parser); + cp_parser_require (parser, CPP_EQ, RT_EQ); + rhs = cp_parser_assignment_expression (parser, false, NULL); + finish_expr_stmt (build_x_modify_expr (EXPR_LOCATION (rhs), + *declp, NOP_EXPR, + rhs, + tf_warning_or_error)); + add_private_clause = true; + } + else + { + *declp = NULL; + cp_parser_abort_tentative_parse (parser); + *initp = cp_parser_expression (parser, false, NULL); + if (*initp) + { + if (TREE_CODE (*initp) == MODIFY_EXPR + || TREE_CODE (*initp) == MODOP_EXPR) + *real_declp = TREE_OPERAND (*initp, 0); + } + } + } + return add_private_clause; +} + /* Parse the restricted form of the for statement allowed by OpenMP. */ static tree @@ -27569,160 +27767,11 @@ cp_parser_omp_for_loop (cp_parser *parser, tree clauses, tree *par_clauses) if (!cp_parser_require (parser, CPP_OPEN_PAREN, RT_OPEN_PAREN)) return NULL; - - init = decl = real_decl = NULL; - this_pre_body = push_stmt_list (); - if (cp_lexer_next_token_is_not (parser->lexer, CPP_SEMICOLON)) - { - /* See 2.5.1 (in OpenMP 3.0, similar wording is in 2.5 standard too): - - init-expr: - var = lb - integer-type var = lb - random-access-iterator-type var = lb - pointer-type var = lb - */ - cp_decl_specifier_seq type_specifiers; - - /* First, try to parse as an initialized declaration. See - cp_parser_condition, from whence the bulk of this is copied. */ - - cp_parser_parse_tentatively (parser); - cp_parser_type_specifier_seq (parser, /*is_declaration=*/true, - /*is_trailing_return=*/false, - &type_specifiers); - if (cp_parser_parse_definitely (parser)) - { - /* If parsing a type specifier seq succeeded, then this - MUST be a initialized declaration. */ - tree asm_specification, attributes; - cp_declarator *declarator; - - declarator = cp_parser_declarator (parser, - CP_PARSER_DECLARATOR_NAMED, - /*ctor_dtor_or_conv_p=*/NULL, - /*parenthesized_p=*/NULL, - /*member_p=*/false); - attributes = cp_parser_attributes_opt (parser); - asm_specification = cp_parser_asm_specification_opt (parser); - - if (declarator == cp_error_declarator) - cp_parser_skip_to_end_of_statement (parser); - - else - { - tree pushed_scope, auto_node; - - decl = start_decl (declarator, &type_specifiers, - SD_INITIALIZED, attributes, - /*prefix_attributes=*/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 ("parenthesized initialization is not allowed in " - "OpenMP % loop"); - else - /* Trigger an error. */ - cp_parser_require (parser, CPP_EQ, RT_EQ); - - init = error_mark_node; - cp_parser_skip_to_end_of_statement (parser); - } - else if (CLASS_TYPE_P (TREE_TYPE (decl)) - || type_dependent_expression_p (decl) - || auto_node) - { - 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_specification, - LOOKUP_ONLYCONVERTING); - if (CLASS_TYPE_P (TREE_TYPE (decl))) - { - vec_safe_push (for_block, this_pre_body); - init = NULL_TREE; - } - else - init = pop_stmt_list (this_pre_body); - this_pre_body = NULL_TREE; - } - else - { - /* Consume '='. */ - 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, - /*init_const_expr_p=*/false, - asm_specification, - LOOKUP_ONLYCONVERTING); - } - - if (pushed_scope) - pop_scope (pushed_scope); - } - } - else - { - cp_id_kind idk; - /* If parsing a type specifier sequence failed, then - this MUST be a simple expression. */ - 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; - - cp_parser_parse_definitely (parser); - cp_parser_require (parser, CPP_EQ, RT_EQ); - rhs = cp_parser_assignment_expression (parser, false, NULL); - finish_expr_stmt (build_x_modify_expr (EXPR_LOCATION (rhs), - decl, NOP_EXPR, - rhs, - tf_warning_or_error)); - add_private_clause = true; - } - else - { - decl = NULL; - cp_parser_abort_tentative_parse (parser); - init = cp_parser_expression (parser, false, NULL); - if (init) - { - if (TREE_CODE (init) == MODIFY_EXPR - || TREE_CODE (init) == MODOP_EXPR) - real_decl = TREE_OPERAND (init, 0); - } - } - } - } + add_private_clause |= + cp_parser_omp_for_loop_init (parser, + /*parsing_openmp=*/true, + &this_pre_body, for_block, + &init, &decl, &real_decl); cp_parser_require (parser, CPP_SEMICOLON, RT_SEMICOLON); if (this_pre_body) { @@ -28743,6 +28792,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); @@ -28808,4 +28867,414 @@ 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; + + if (token->type == CPP_SEMICOLON) + { + error_at (loc, "expected induction variable"); + 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); + } + + tree this_pre_body, decl, real_decl; + (void) cp_parser_omp_for_loop_init (parser, + /*parsing_openmp=*/false, + &this_pre_body, + /*for_block=*/NULL, + init, &decl, &real_decl); + 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; + } + 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, + /*scan_body=*/false); + } + 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 3d8bb74..4fbc655 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 ee3503c..9d91d99 100644 --- a/gcc/cp/semantics.c +++ b/gcc/cp/semantics.c @@ -5145,6 +5145,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 3ab558c..67be47b 100644 --- a/gcc/gimple-pretty-print.c +++ b/gcc/gimple-pretty-print.c @@ -1097,6 +1097,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 (); } @@ -1125,6 +1128,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 9f29561..6eab2ad 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 3b3adb3..7273d35 100644 --- a/gcc/gimplify.c +++ b/gcc/gimplify.c @@ -4710,6 +4710,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: @@ -6583,7 +6584,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); @@ -6623,7 +6625,8 @@ gimplify_omp_for (tree *expr_p, gimple_seq *pre_p) for (i = 0; i < TREE_VEC_LENGTH (OMP_FOR_INIT (for_stmt)); i++) { t = TREE_VEC_ELT (OMP_FOR_INIT (for_stmt), i); - gcc_assert (TREE_CODE (t) == MODIFY_EXPR); + gcc_assert (TREE_CODE (t) == MODIFY_EXPR + || TREE_CODE (t) == INIT_EXPR); decl = TREE_OPERAND (t, 0); gcc_assert (DECL_P (decl)); gcc_assert (INTEGRAL_TYPE_P (TREE_TYPE (decl)) @@ -6708,13 +6711,21 @@ gimplify_omp_for (tree *expr_p, gimple_seq *pre_p) { case PREINCREMENT_EXPR: case POSTINCREMENT_EXPR: - t = build_int_cst (TREE_TYPE (decl), 1); - if (c) - OMP_CLAUSE_LINEAR_STEP (c) = t; - t = build2 (PLUS_EXPR, TREE_TYPE (decl), var, t); - t = build2 (MODIFY_EXPR, TREE_TYPE (var), var, t); - TREE_VEC_ELT (OMP_FOR_INCR (for_stmt), i) = t; - break; + { + tree decl = TREE_OPERAND (t, 0); + + // The c_omp_for_incr_canonicalize_ptr() should have been + // called to massage things appropriately. + gcc_assert (!POINTER_TYPE_P (TREE_TYPE (decl))); + + t = build_int_cst (TREE_TYPE (decl), 1); + if (c) + OMP_CLAUSE_LINEAR_STEP (c) = t; + t = build2 (PLUS_EXPR, TREE_TYPE (decl), var, t); + t = build2 (MODIFY_EXPR, TREE_TYPE (var), var, t); + TREE_VEC_ELT (OMP_FOR_INCR (for_stmt), i) = t; + break; + } case PREDECREMENT_EXPR: case POSTDECREMENT_EXPR: @@ -6809,6 +6820,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 (); } @@ -7751,6 +7763,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 d24270f..2250451 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); @@ -933,7 +937,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. */ @@ -1864,7 +1868,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"); @@ -1874,7 +1878,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: @@ -2378,7 +2382,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; @@ -2835,7 +2839,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); } @@ -2914,7 +2918,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) @@ -3009,7 +3013,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 @@ -5726,7 +5730,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 @@ -6831,7 +6835,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 ()); } namespace { @@ -8000,7 +8004,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, @@ -8120,12 +8124,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; @@ -8308,7 +8333,7 @@ diagnose_omp_structured_block_errors (void) static bool gate_diagnose_omp_blocks (void) { - return flag_openmp != 0; + return flag_openmp || flag_enable_cilkplus; } namespace { 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 0000000..e8e2066 --- /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 0000000..6d84791 --- /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 0000000..71589c2 --- /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 0000000..579b718 --- /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 0000000..e9e140d --- /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 induction variable" } + 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 "induction 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 0000000..8660627 --- /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 0000000..2da8235 --- /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 0000000..7075a44 --- /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/reduction-1.c b/gcc/testsuite/c-c++-common/cilk-plus/PS/reduction-1.c new file mode 100644 index 0000000..81a1abb --- /dev/null +++ b/gcc/testsuite/c-c++-common/cilk-plus/PS/reduction-1.c @@ -0,0 +1,38 @@ +/* { dg-do run { xfail *-*-* } } */ +/* { dg-options "-O3 -fcilkplus" } */ + +/* FIXME: This test has been xfailed until reductions are fixed. */ + +int argc = 1; + +/* This is a simple vectorization test. It tests if reduction works + and if it can vectorize the 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/reduction-2.c b/gcc/testsuite/c-c++-common/cilk-plus/PS/reduction-2.c new file mode 100644 index 0000000..912d5f5 --- /dev/null +++ b/gcc/testsuite/c-c++-common/cilk-plus/PS/reduction-2.c @@ -0,0 +1,38 @@ +/* { dg-do run { xfail *-*-* } } */ +/* { dg-options "-O3 -fcilkplus" } */ + +/* FIXME: This test has been xfailed until reductions are fixed. */ + +#include + +#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/reduction-3.c b/gcc/testsuite/c-c++-common/cilk-plus/PS/reduction-3.c new file mode 100644 index 0000000..3508c02 --- /dev/null +++ b/gcc/testsuite/c-c++-common/cilk-plus/PS/reduction-3.c @@ -0,0 +1,43 @@ +/* { dg-do run { xfail *-*-* } } */ +/* { dg-options "-O3 -fcilkplus" } */ + +/* FIXME: This test has been xfailed until reductions are fixed. */ + +#define N 256 +#if HAVE_IO +#include +#endif +#include + +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/run-1.c b/gcc/testsuite/c-c++-common/cilk-plus/PS/run-1.c new file mode 100644 index 0000000..c8fe1c7 --- /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 + +#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 0000000..2c59de9 --- /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 0000000..9aa4a68 --- /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 7e0fda5..fa9246c 100644 --- a/gcc/testsuite/g++.dg/cilk-plus/cilk-plus.exp +++ b/gcc/testsuite/g++.dg/cilk-plus/cilk-plus.exp @@ -16,7 +16,6 @@ # Written by Balaji V. Iyer - load_lib g++-dg.exp if { ![check_effective_target_cilkplus] } { @@ -24,6 +23,13 @@ if { ![check_effective_target_cilkplus] } { } 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 0000000..2295d21 --- /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 0000000..d30e057 --- /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 710218e..e9d0428 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 0000000..253acee --- /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 2533feb..4eb43d6 100644 --- a/gcc/testsuite/gcc.dg/cilk-plus/cilk-plus.exp +++ b/gcc/testsuite/gcc.dg/cilk-plus/cilk-plus.exp @@ -24,6 +24,13 @@ if { ![check_effective_target_cilkplus] } { } 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 0000000..4fb5342 --- /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 0000000..dc0a41e --- /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 0000000..9ec3293 --- /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 69e4006..ab914ef 100644 --- a/gcc/tree-pretty-print.c +++ b/gcc/tree-pretty-print.c @@ -2212,6 +2212,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 f825aad..552c704 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 eb017e5..624a3e7 100644 --- a/gcc/tree.h +++ b/gcc/tree.h @@ -1795,12 +1795,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)