From patchwork Mon Apr 22 22:05:03 2013 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: Aldy Hernandez X-Patchwork-Id: 238673 Return-Path: X-Original-To: incoming@patchwork.ozlabs.org Delivered-To: patchwork-incoming@bilbo.ozlabs.org Received: from sourceware.org (server1.sourceware.org [209.132.180.131]) (using TLSv1 with cipher DHE-RSA-AES256-SHA (256/256 bits)) (Client CN "localhost", Issuer "www.qmailtoaster.com" (not verified)) by ozlabs.org (Postfix) with ESMTPS id 48A032C00F8 for ; Tue, 23 Apr 2013 08:05:53 +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=Lu6sZ7RlOVce4Xdym ipVveDEv7GZVX7rRkg909IIo79ifq0CclY5WD2P0eD67WSgnN3UfRuw38CUEKhSQ 5rrdDlcEt9qVjjhnlM5HBSXzJgC4yUFI9/jgVTLG94smXXA3Sn3ZhogA7P/jAsFo nxv8e0vU2WYmalP0/lwBcU6ZUg= 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=t8qEhN4uHTz9TQMjG1vvWN+ J4QM=; b=vdPsvL0k1HBoc6gzfgeIZockp3XL8I0wwG+X43fF9f0kHA7h1yWShwN Yfb23TuADkDs2Lsyszzw6GN12QgJFm19bsQK8bu5T6srHL0/wfN0vmaPK6qe8LfP h5CMtTCSaug1DgoAFl+rsXpuy/dS0YBOfKFKmZPLCfLOyMllevec= Received: (qmail 2017 invoked by alias); 22 Apr 2013 22:05:46 -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 2006 invoked by uid 89); 22 Apr 2013 22:05:45 -0000 X-Spam-SWARE-Status: No, score=-7.5 required=5.0 tests=AWL, BAYES_00, KHOP_THREADED, RCVD_IN_DNSWL_HI, RCVD_IN_HOSTKARMA_W, RP_MATCHES_RCVD, SPF_HELO_PASS, SPF_PASS, TW_EG, TW_TM, TW_XT autolearn=ham version=3.3.1 Received: from mx1.redhat.com (HELO mx1.redhat.com) (209.132.183.28) by sourceware.org (qpsmtpd/0.84/v0.84-167-ge50287c) with ESMTP; Mon, 22 Apr 2013 22:05:07 +0000 Received: from int-mx12.intmail.prod.int.phx2.redhat.com (int-mx12.intmail.prod.int.phx2.redhat.com [10.5.11.25]) by mx1.redhat.com (8.14.4/8.14.4) with ESMTP id r3MM55Qu023808 (version=TLSv1/SSLv3 cipher=DHE-RSA-AES256-SHA bits=256 verify=OK); Mon, 22 Apr 2013 18:05:05 -0400 Received: from houston.quesejoda.com (vpn-57-174.rdu2.redhat.com [10.10.57.174]) by int-mx12.intmail.prod.int.phx2.redhat.com (8.14.4/8.14.4) with ESMTP id r3MM53IZ000532; Mon, 22 Apr 2013 18:05:04 -0400 Message-ID: <5175B40F.7040709@redhat.com> Date: Mon, 22 Apr 2013 17:05:03 -0500 From: Aldy Hernandez User-Agent: Mozilla/5.0 (X11; Linux x86_64; rv:17.0) Gecko/20130311 Thunderbird/17.0.4 MIME-Version: 1.0 To: Jakub Jelinek CC: Richard Henderson , gcc-patches@gcc.gnu.org, "Iyer, Balaji V" Subject: Re: [gomp4] Some progress on #pragma omp simd References: <20130419132957.GE12880@tucnak.redhat.com> In-Reply-To: <20130419132957.GE12880@tucnak.redhat.com> X-Virus-Found: No On 04/19/13 08:29, Jakub Jelinek wrote: > Hi! > > I've committed the following patch to gomp4 branch. > #pragma omp simd loops now are handled with all its clauses from parsing up > to and including omp expansion, so should actually run correctly, though > haven't added any runtime testcases yet. I like it. Thanks for working on this. I've been working on rewriting the <#pragma simd> support on the cilkplus branch to use a similar approach to what you do for openmp, especially since both constructs seem to behave similarly, with the exception of the "vectorlength" clause in Cilk Plus. Attached is a patch against yours, doing so. The idea is that <#prama omp simd> and <#pragma simd> are pretty much the same thing, so we can probably get away with outputting the same OMP_SIMD tree code and letting omp do it's thing. I am also ignoring the "vectorlength" clause as you have done with safelen, waiting for Richi's loop preservation patch. It seems that the Cilk Plus folk have not finalized the assert clause, and it's currently missing from the current spec. I have left the assert clause in, as it seems they'll include something similar with a different syntax. Otherwise, I'm using the same OMP_SIMD codes, as well as reusing your OMP_CLAUSE_LINEAR*. For the firstprivate, lastprivate, private, and reduction clauses, I'm reusing even the parsing bits for OMP since the Cilk Plus spec uses the same exact syntax. Perhaps eventually we could use some bits on the OMP_SIMD tree to differentiate an OMP_SIMD from a Cilk SIMD variant, and then use those to typecheck that the vectorlength and assert clauses are only used for Cilk Plus' #pragma simd. I am missing a few minor things (some typechecking restrictions for longjmp() inside for-loop bodies, etc), but the parsing is basically done. See the plethora of tests :). How does this look, or do would you prefer another approach? commit b2270ce0ab7ee4eb37b68b706fcf2e15941eb6ef Author: Aldy Hernandez Date: Mon Apr 22 13:54:42 2013 -0500 Rewrite Cilk Plus <#pragma simd> parsing and rewrite to use gomp4's OMP_SIMD infrastructure. diff --git a/gcc/Makefile.in b/gcc/Makefile.in index 54ea04f..e0d6092 100644 --- a/gcc/Makefile.in +++ b/gcc/Makefile.in @@ -1137,6 +1137,7 @@ C_COMMON_OBJS = c-family/c-common.o c-family/c-cppbuiltin.o c-family/c-dump.o \ c-family/c-format.o c-family/c-gimplify.o c-family/c-lex.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-cilkplus.o \ c-family/c-semantics.o c-family/c-ada-spec.o tree-mudflap.o # Language-independent object files. @@ -1966,6 +1967,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..d5f069f --- /dev/null +++ b/gcc/c-family/c-cilkplus.c @@ -0,0 +1,278 @@ +/* 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 (EXPR_HAS_LOCATION (incr)) + loc = EXPR_LOCATION (incr); + + if (!incr) + { + error_at (loc, "missing increment"); + return error_mark_node; + } + + switch (TREE_CODE (incr)) + { + case POSTINCREMENT_EXPR: + case PREINCREMENT_EXPR: + case POSTDECREMENT_EXPR: + case PREDECREMENT_EXPR: + if (TREE_OPERAND (incr, 0) != decl) + break; + + // Bah... canonicalize into whatever OMP_FOR_INCR needs. + if (POINTER_TYPE_P (TREE_TYPE (decl)) + && TREE_OPERAND (incr, 1)) + { + tree t = fold_convert_loc (loc, + sizetype, TREE_OPERAND (incr, 1)); + + if (TREE_CODE (incr) == POSTDECREMENT_EXPR + || TREE_CODE (incr) == PREDECREMENT_EXPR) + t = fold_build1_loc (loc, NEGATE_EXPR, sizetype, t); + t = fold_build_pointer_plus (decl, t); + incr = build2 (MODIFY_EXPR, void_type_node, decl, t); + } + return incr; + + case MODIFY_EXPR: + { + tree rhs; + + if (TREE_OPERAND (incr, 0) != decl) + break; + + rhs = TREE_OPERAND (incr, 1); + if (TREE_CODE (rhs) == PLUS_EXPR + && (TREE_OPERAND (rhs, 0) == decl + || TREE_OPERAND (rhs, 1) == decl) + && INTEGRAL_TYPE_P (TREE_TYPE (rhs))) + return incr; + else if (TREE_CODE (rhs) == MINUS_EXPR + && TREE_OPERAND (rhs, 0) == decl + && INTEGRAL_TYPE_P (TREE_TYPE (rhs))) + return incr; + // Otherwise fail because only PLUS_EXPR and MINUS_EXPR are + // allowed. + break; + } + + default: + break; + } + + error_at (loc, "invalid increment expression"); + return error_mark_node; +} + +/* 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. INCR is the + increment expression. BODY is the body of the LOOP. */ + +static bool +c_check_cilk_loop (location_t loc, tree decl, tree cond, tree incr, tree body) +{ + if (decl == error_mark_node + || cond == error_mark_node + || incr == error_mark_node + || body == error_mark_node) + return false; + + /* Validate the initialization. */ + gcc_assert (decl != NULL); + if (TREE_THIS_VOLATILE (decl)) + { + error_at (loc, "induction variable cannot be volatile"); + return false; + } + if (DECL_EXTERNAL (decl)) + { + error_at (loc, "induction variable cannot be extern"); + return false; + } + if (TREE_STATIC (decl)) + { + error_at (loc, "induction variable cannot be static"); + return false; + } + if (DECL_REGISTER (decl)) + { + error_at (loc, "induction variable cannot be declared register"); + return false; + } + if (!INTEGRAL_TYPE_P (TREE_TYPE (decl)) + && !POINTER_TYPE_P (TREE_TYPE (decl))) + { + error_at (loc, "initialization variable must be of integral " + "or pointer type"); + return false; + } + + /* Validate the condition. */ + if (!cond) + { + error_at (loc, "missing condition"); + return false; + } + bool cond_ok = false; + if (TREE_CODE (cond) == NE_EXPR + || TREE_CODE (cond) == LT_EXPR + || TREE_CODE (cond) == LE_EXPR + || TREE_CODE (cond) == GT_EXPR + || TREE_CODE (cond) == GE_EXPR) + { + /* Comparison must either be: + DECL 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 the increment. */ + incr = c_check_cilk_loop_incr (loc, decl, incr); + if (incr == error_mark_node) + return false; + + return true; + } + +/* 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. + + Returns the generated statement. */ + +tree +c_finish_cilk_simd_loop (location_t loc, + tree decl, + tree init, tree cond, tree incr, + tree body, + tree clauses) +{ + location_t rhs_loc; + + if (!c_check_cilk_loop (loc, decl, cond, incr, body)) + return NULL; + + /* In the case of "for (int i = 0...)", init will be a decl. It should + have a DECL_INITIAL that we can turn into an assignment. */ + if (init == decl) + { + rhs_loc = DECL_SOURCE_LOCATION (decl); + + init = DECL_INITIAL (decl); + if (init == NULL) + { + error_at (rhs_loc, "%qE is not initialized", decl); + init = integer_zero_node; + return NULL; + } + + init = build_modify_expr (loc, decl, NULL_TREE, NOP_EXPR, rhs_loc, + init, NULL_TREE); + } + gcc_assert (TREE_CODE (init) == MODIFY_EXPR); + 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; + + // FIXME: What should we do about nested loops? Look at specs. + + /* The OpenMP <#pragma omp simd> construct is exactly the same as + the Cilk Plus one, with the exception of the vectorlength() + clause in Cilk Plus. Emitting an OMP_SIMD simlifies + everything. */ + tree t = make_node (OMP_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) = 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) +{ + // FIXME: "...no variable shall be the subject of more than one + // linear clause". Verify and check for this. + + // FIXME: Also, do whatever we were doing before in + // same_var_in_multiple_lists_p, but rewrite to use OMP_CLAUSEs. + + return clauses; +} diff --git a/gcc/c-family/c-pragma.c b/gcc/c-family/c-pragma.c index b03ddc1..c05b8d0 100644 --- a/gcc/c-family/c-pragma.c +++ b/gcc/c-family/c-pragma.c @@ -1352,6 +1352,12 @@ init_pragma (void) omp_pragmas[i].id, true, true); } + if (flag_enable_cilk && !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 cd121d4..2ff5a00 100644 --- a/gcc/c-family/c-pragma.h +++ b/gcc/c-family/c-pragma.h @@ -60,6 +60,9 @@ typedef enum pragma_kind { PRAGMA_OMP_THREADPRIVATE, PRAGMA_OMP_TEAMS, + /* Top level clause to handle all Cilk Plus pragma simd clauses. */ + PRAGMA_CILK_SIMD, + PRAGMA_GCC_PCH_PREPROCESS, PRAGMA_FIRST_EXTERNAL @@ -109,6 +112,19 @@ typedef enum pragma_omp_clause { PRAGMA_OMP_CLAUSE_UNTIED } pragma_omp_clause; +/* All Cilk Plus #pragma omp clauses. */ +typedef enum pragma_cilk_clause { + PRAGMA_CILK_CLAUSE_NONE = 0, + PRAGMA_CILK_CLAUSE_NOASSERT, + PRAGMA_CILK_CLAUSE_ASSERT, + 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-family/c.opt b/gcc/c-family/c.opt index 10ae84d..e502b3f 100644 --- a/gcc/c-family/c.opt +++ b/gcc/c-family/c.opt @@ -839,6 +839,10 @@ Recognize built-in functions fbuiltin- C ObjC C++ ObjC++ Joined +fcilkplus +C ObjC C++ ObjC++ LTO Report Var(flag_enable_cilk) Init(0) +Enable Cilk + fcanonical-system-headers C ObjC C++ ObjC++ Where shorter, use canonicalized paths to systems headers. diff --git a/gcc/c/c-parser.c b/gcc/c/c-parser.c index 5b06803..41d44a4 100644 --- a/gcc/c/c-parser.c +++ b/gcc/c/c-parser.c @@ -1217,6 +1217,11 @@ 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); + /* Parse a translation unit (C90 6.7, C99 6.9). translation-unit: @@ -8622,6 +8627,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) { @@ -10664,7 +10676,457 @@ 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_cilk) + { + 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: + assert */ + +static tree +c_parser_cilk_clause_assert (c_parser *parser, tree clauses) +{ + check_no_duplicate_clause (clauses, OMP_CLAUSE_CILK_ASSERT, "assert"); + + location_t loc = c_parser_peek_token (parser)->location; + tree c = build_omp_clause (loc, OMP_CLAUSE_CILK_ASSERT); + OMP_CLAUSE_CHAIN (c) = clauses; + return c; +} + +/* Cilk Plus: + noassert */ + +static tree +c_parser_cilk_clause_noassert (c_parser *parser ATTRIBUTE_UNUSED, + tree clauses) +{ + /* Only check that we don't already have an assert clause. */ + check_no_duplicate_clause (clauses, OMP_CLAUSE_CILK_ASSERT, "assert"); + + return clauses; +} + +/* Cilk Plus: + vectorlength (constant-expression-list ) + + constant-expression-list: + constant-expression + constant-expression-list , constant-expression */ + +static tree +c_parser_cilk_clause_vectorlength (c_parser *parser, tree clauses) +{ + check_no_duplicate_clause (clauses, OMP_CLAUSE_CILK_VECTORLENGTH, + "vectorlength"); + + if (!c_parser_require (parser, CPP_OPEN_PAREN, "expected %<(%>")) + return clauses; + + location_t loc = c_parser_peek_token (parser)->location; + while (true) + { + 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 + { + tree u = build_omp_clause (loc, OMP_CLAUSE_CILK_VECTORLENGTH); + OMP_CLAUSE_CILK_VECTORLENGTH_EXPR (u) = expr; + OMP_CLAUSE_CHAIN (u) = clauses; + clauses = u; + } + + if (c_parser_next_token_is (parser, CPP_CLOSE_PAREN)) + { + c_parser_consume_token (parser); + return clauses; + } + if (c_parser_next_token_is (parser, CPP_COMMA)) + c_parser_consume_token (parser); + } + + 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, "noassert")) + result = PRAGMA_CILK_CLAUSE_NOASSERT; + else if (!strcmp (p, "assert")) + result = PRAGMA_CILK_CLAUSE_ASSERT; + else 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_NOASSERT: + clauses = c_parser_cilk_clause_noassert (parser, clauses); + break; + case PRAGMA_CILK_CLAUSE_ASSERT: + clauses = c_parser_cilk_clause_assert (parser, clauses); + break; + case PRAGMA_CILK_CLAUSE_VECTORLENGTH: + clauses = c_parser_cilk_clause_vectorlength (parser, clauses); + break; + case PRAGMA_CILK_CLAUSE_LINEAR: + clauses = c_parser_cilk_clause_linear (parser, clauses); + break; + case PRAGMA_CILK_CLAUSE_PRIVATE: + /* Use the OpenMP counterpart. */ + clauses = c_parser_omp_clause_private (parser, clauses); + break; + case PRAGMA_CILK_CLAUSE_FIRSTPRIVATE: + /* Use the OpenMP counterpart. */ + clauses = c_parser_omp_clause_firstprivate (parser, clauses); + break; + case PRAGMA_CILK_CLAUSE_LASTPRIVATE: + /* Use the OpenMP counterpart. */ + clauses = c_parser_omp_clause_lastprivate (parser, clauses); + break; + case PRAGMA_CILK_CLAUSE_REDUCTION: + /* Use the OpenMP counterpart. */ + clauses = c_parser_omp_clause_reduction (parser, clauses); + break; + default: + c_parser_error (parser, "expected %<#pragma simd%> clause"); + goto saw_error; + } + } + + saw_error: + c_parser_skip_to_pragma_eol (parser); + return c_finish_cilk_clauses (clauses); +} + +/* Parse the restriction form of the for statement allowed by + Cilk Plus. This function parses both the _CILK_FOR construct as + well as the for loop following a <#pragma simd> construct, both of + which have the same syntactic restrictions. + + FOR_KEYWORD can be either RID_CILK_FOR or RID_FOR, for parsing + _cilk_for or the <#pragma simd> for loop construct respectively. + + (NOTE: For now, only RID_FOR is handled). + + For a <#pragma simd>, CLAUSES are the clauses that should have been + previously parsed. If there are none, or if we are parsing a + _Cilk_for instead, this will be NULL. */ + +static void +c_parser_cilk_for_statement (c_parser *parser, enum rid for_keyword, + tree clauses) +{ + tree init, decl, cond, stmt; + tree block, incr, save_break, save_cont, body; + location_t loc; + bool fail = false; + + gcc_assert (/*for_keyword == RID_CILK_FOR || */for_keyword == RID_FOR); + + if (!c_parser_next_token_is_keyword (parser, for_keyword)) + { + if (for_keyword == RID_FOR) + c_parser_error (parser, "for statement expected"); + else + c_parser_error (parser, "_Cilk_for statement expected"); + return; + } + + loc = c_parser_peek_token (parser)->location; + c_parser_consume_token (parser); + + block = c_begin_compound_stmt (true); + + if (!c_parser_require (parser, CPP_OPEN_PAREN, "expected %<(%>")) + { + add_stmt (c_end_compound_stmt (loc, block, true)); + return; + } + + /* Parse the initialization declaration. */ + if (c_parser_next_tokens_start_declaration (parser)) + { + c_parser_declaration_or_fndef (parser, true, false, false, + false, false, NULL); + decl = check_for_loop_decls (loc, flag_isoc99); + if (decl == NULL) + goto error_init; + if (DECL_INITIAL (decl) == error_mark_node) + decl = error_mark_node; + init = decl; + } + else if (c_parser_next_token_is (parser, CPP_NAME) + && c_parser_peek_2nd_token (parser)->type == CPP_EQ) + { + struct c_expr decl_exp; + struct c_expr init_exp; + location_t init_loc; + + decl_exp = c_parser_postfix_expression (parser); + decl = decl_exp.value; + + c_parser_require (parser, CPP_EQ, "expected %<=%>"); + + init_loc = c_parser_peek_token (parser)->location; + init_exp = c_parser_expr_no_commas (parser, NULL); + init_exp = default_function_array_read_conversion (init_loc, + init_exp); + init = build_modify_expr (init_loc, decl, decl_exp.original_type, + NOP_EXPR, init_loc, init_exp.value, + init_exp.original_type); + init = c_process_expr_stmt (init_loc, init); + + c_parser_skip_until_found (parser, CPP_SEMICOLON, "expected %<;%>"); + } + else + { + error_init: + c_parser_error (parser, + "expected iteration declaration or initialization"); + c_parser_skip_until_found (parser, CPP_CLOSE_PAREN, + "expected %<)%>"); + return; + } + + /* Parse the loop condition. */ + cond = NULL_TREE; + if (c_parser_next_token_is_not (parser, CPP_SEMICOLON)) + { + location_t cond_loc = c_parser_peek_token (parser)->location; + struct c_expr cond_expr = c_parser_binary_expression (parser, NULL, + NULL); + + 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; + + // FIXME: Disallow the following constructs within a SIMD loop: + // + // RETURN + // GOTO + // _Cilk_spawn + // _Cilk_for + // OpenMP directive or construct + // Calls to setjmp() + + if (!fail) + { + /* + // FIXME: Uncomment when RID_CILK_FOR is implemented. + if (for_keyword == RID_CILK_FOR) + c_finish_cilk_loop (loc, decl, cond, incr, body, grain); + else + */ + c_finish_cilk_simd_loop (loc, decl, init, cond, incr, body, clauses); + } + + stmt = c_end_compound_stmt (loc, block, true); + add_stmt (stmt); + c_break_label = save_break; + c_cont_label = save_cont; +} + +/* Main entry point for parsing Cilk Plus <#pragma simd> for + loops. */ + +static void +c_parser_cilk_simd_construct (c_parser *parser) +{ + tree clauses = c_parser_cilk_all_clauses (parser); + + /* For <#pragma simd> we will be generating OMP_SIMD's and let the + OpenMP mechanism handle everything. */ + if (!flag_openmp) + flag_openmp = true; + + c_parser_cilk_for_statement (parser, RID_FOR, clauses); +} + /* Parse a transaction attribute (GCC Extension). transaction-attribute: diff --git a/gcc/c/c-tree.h b/gcc/c/c-tree.h index c4210a5..0fd9cc6 100644 --- a/gcc/c/c-tree.h +++ b/gcc/c/c-tree.h @@ -642,6 +642,11 @@ extern tree c_build_va_arg (location_t, tree, tree); extern tree c_finish_transaction (location_t, tree, int); extern bool c_tree_equal (tree, tree); +/* In c-cilkplus.c */ +extern tree c_finish_cilk_simd_loop (location_t, tree, tree, tree, tree, + tree, tree); +extern tree c_finish_cilk_clauses (tree); + /* Set to 0 at beginning of a function definition, set to 1 if a return statement that specifies a return value is seen. */ diff --git a/gcc/gimplify.c b/gcc/gimplify.c index f6b6717..013fe43 100644 --- a/gcc/gimplify.c +++ b/gcc/gimplify.c @@ -6337,6 +6337,8 @@ gimplify_scan_omp_clauses (tree *list_p, gimple_seq *pre_p, case OMP_CLAUSE_MERGEABLE: case OMP_CLAUSE_PROC_BIND: case OMP_CLAUSE_SAFELEN: + case OMP_CLAUSE_CILK_ASSERT: + case OMP_CLAUSE_CILK_VECTORLENGTH: break; case OMP_CLAUSE_ALIGNED: @@ -6528,6 +6530,8 @@ gimplify_adjust_omp_clauses (tree *list_p) case OMP_CLAUSE_MERGEABLE: case OMP_CLAUSE_PROC_BIND: case OMP_CLAUSE_SAFELEN: + case OMP_CLAUSE_CILK_ASSERT: + case OMP_CLAUSE_CILK_VECTORLENGTH: break; default: diff --git a/gcc/omp-low.c b/gcc/omp-low.c index 58117d9..b38ed9b 100644 --- a/gcc/omp-low.c +++ b/gcc/omp-low.c @@ -1491,6 +1491,8 @@ scan_sharing_clauses (tree clauses, omp_context *ctx) case OMP_CLAUSE_PROC_BIND: case OMP_CLAUSE_SAFELEN: case OMP_CLAUSE_ALIGNED: + case OMP_CLAUSE_CILK_ASSERT: + case OMP_CLAUSE_CILK_VECTORLENGTH: break; default: @@ -1547,6 +1549,8 @@ scan_sharing_clauses (tree clauses, omp_context *ctx) case OMP_CLAUSE_PROC_BIND: case OMP_CLAUSE_SAFELEN: case OMP_CLAUSE_ALIGNED: + case OMP_CLAUSE_CILK_ASSERT: + case OMP_CLAUSE_CILK_VECTORLENGTH: break; default: diff --git a/gcc/testsuite/gcc.dg/cilk-plus/cilk-simd/compile/cilk-simd-compile.exp b/gcc/testsuite/gcc.dg/cilk-plus/cilk-simd/compile/cilk-simd-compile.exp new file mode 100644 index 0000000..154bb8c --- /dev/null +++ b/gcc/testsuite/gcc.dg/cilk-plus/cilk-simd/compile/cilk-simd-compile.exp @@ -0,0 +1,23 @@ +# Copyright (C) 2013 Free Software Foundation, Inc. + +# This program is free software; you can redistribute it and/or modify +# it under the terms of the GNU General Public License as published by +# the Free Software Foundation; either version 3 of the License, or +# (at your option) any later version. +# +# This program is distributed in the hope that it will be useful, +# but WITHOUT ANY WARRANTY; without even the implied warranty of +# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +# GNU General Public License for more details. +# +# You should have received a copy of the GNU General Public License +# along with GCC; see the file COPYING3. If not see +# . + +load_lib gcc-dg.exp + +set OPTS "-fcilkplus -c -ftree-vectorize" + +dg-init +dg-runtest [lsort [glob -nocomplain $srcdir/$subdir/*.c]] " $OPTS" " " +dg-finish diff --git a/gcc/testsuite/gcc.dg/cilk-plus/cilk-simd/compile/clauses1.c b/gcc/testsuite/gcc.dg/cilk-plus/cilk-simd/compile/clauses1.c new file mode 100644 index 0000000..ae01db3 --- /dev/null +++ b/gcc/testsuite/gcc.dg/cilk-plus/cilk-simd/compile/clauses1.c @@ -0,0 +1,84 @@ +/* { dg-do compile } */ +/* { dg-options "-O3 -std=c99 -fcilkplus" } */ + +volatile int *a, *b; + +void foo() +{ + int i, j, k; + +#pragma simd assert aoeu /* { dg-error "expected '#pragma simd' clause" } */ + for (int i=0; i < 1000; ++i) + a[i] = b[j]; + +#pragma simd noassert aoeu /* { dg-error "expected '#pragma simd' clause" } */ + for (int i=0; i < 1000; ++i) + a[i] = b[j]; + +#pragma simd assert noassert /* { dg-error "too many 'assert' clauses" } */ + 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 /* { 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) + for (int i=0; i < 1000; ++i) + a[i] = b[j]; + +#pragma simd vectorlength(i) /* { dg-error "vectorlength must be an integer" } */ + 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" } */ + for (int i=0; i < 1000; ++i) + a[i] = b[j]; + +#pragma simd linear(blah2, 36) + /* { dg-error "'blah2' undeclared" "undeclared" { target *-*-* } 50 } */ + /* { dg-error "expected '\\)'" "expected" { target *-*-* } 50 } */ + 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 assert linear(j : 4) vectorlength(4) + for (i=0; i < 1000; ++i) + a[i] = b[j]; +} diff --git a/gcc/testsuite/gcc.dg/cilk-plus/cilk-simd/compile/clauses2.c b/gcc/testsuite/gcc.dg/cilk-plus/cilk-simd/compile/clauses2.c new file mode 100644 index 0000000..6be6085 --- /dev/null +++ b/gcc/testsuite/gcc.dg/cilk-plus/cilk-simd/compile/clauses2.c @@ -0,0 +1,19 @@ +/* { dg-do compile } */ +/* { dg-options "-O3 -std=c99 -fcilkplus -fdump-tree-original" } */ + +volatile int *a, *b; + +void foo() +{ + int i, j, k; + +#pragma simd assert linear(j : 4, k) vectorlength(4) + for (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 "cilk_vectorlength\\(4\\)" 1 "original" } } */ +/* { dg-final { scan-tree-dump-times "cilk_assert" 1 "original" } } */ +/* { dg-final { cleanup-tree-dump "original" } } */ diff --git a/gcc/testsuite/gcc.dg/cilk-plus/cilk-simd/compile/for1.c b/gcc/testsuite/gcc.dg/cilk-plus/cilk-simd/compile/for1.c new file mode 100644 index 0000000..38700e4 --- /dev/null +++ b/gcc/testsuite/gcc.dg/cilk-plus/cilk-simd/compile/for1.c @@ -0,0 +1,135 @@ +/* { dg-do compile } */ +/* { dg-options "-O3 -std=c99 -fcilkplus" } */ + +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]; + + // Declaration and initialization is allowed. +#pragma simd + for (int i=0; i < 1000; i++) + a[i] = b[j]; + + // Empty initialization is not allowed. +#pragma simd + for (; i < 5; ++i) // { dg-error "expected iteration decl" } + a[i] = i; + + // Empty condition is not allowed. +#pragma simd + for (i=0; ; ++i) /* { dg-error "missing condition" } */ + a[i] = i; + + // Empty increment is not allowed. +#pragma simd + for (i=0; i < 1234; ) /* { dg-error "missing increment" } */ + a[i] = i*2; + +#pragma simd + i = 5; /* { dg-error "for statement expected" } */ + + // Initialization variables must be either integral or pointer types. + struct S { + int i; + }; +#pragma simd + for (struct S ss = { 0 }; ss.i <= 1000; ++ss.i) /* { dg-error "initialization variable must be of integral or pointer type" } */ + a[ss.i] = b[ss.i]; + + #pragma simd + for (float f=0.0; f < 15.0; ++f) /* { dg-error "must be of integral" } */ + a[(int)f] = (int) f; + + // Pointers are OK. + #pragma simd + for (int *i=c; i < &c[100]; ++i) + *a = '5'; + + // Condition of '==' is not allowed. +#pragma simd + for (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 (i=0; i+j < 1234; ++i) /* { dg-error "invalid controlling predicate" } */ + a[i] = b[i]; + + // Likewise. +#pragma simd + for (i=0; 1234 < i + j; ++i) /* { dg-error "invalid controlling predicate" } */ + a[i] = b[i]; + + // Likewise, this is ok. +#pragma simd + for (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 (i=0; (char)i < 1234; ++i) /* { dg-error "invalid controlling predicate" } */ + a[i] = b[i]; + + // ?? This condition gets folded into "i != 0" by + // c_parser_cilk_for_statement(). Does this count as a "!=", or is + // this disallowed? Assume it is allowed. +#pragma simd + for (i=100; i; --i) + a[i] = b[i]; + + // Increment must be on the induction variable. +#pragma simd + for (i=0; i < 100; j++) /* { dg-error "invalid increment expression" } */ + a[i] = b[i]; + + // Likewise. +#pragma simd + for (i=0; i < 100; j = i + 1) /* { dg-error "invalid increment expression" } */ + a[i] = b[i]; + + // Likewise. +#pragma simd + for (i=0; i < 100; i = j + 1) /* { dg-error "invalid increment expression" } */ + a[i] = b[i]; + +#pragma simd + for (i=0; i < 100; i = i + 5) + a[i] = b[i]; + + // Only PLUS and MINUS increments are allowed. +#pragma simd + for (i=0; i < 100; i *= 5) /* { dg-error "invalid increment expression" } */ + a[i] = b[i]; + +#pragma simd + for (i=0; i < 100; i -= j) + a[i] = b[i]; + +#pragma simd + for (i=0; i < 100; i = i + j) + a[i] = b[i]; + +#pragma simd + for (i=0; i < 100; i = j + i) + a[i] = b[i]; + +#pragma simd + for (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/gcc.dg/cilk-plus/cilk-simd/compile/for2.c b/gcc/testsuite/gcc.dg/cilk-plus/cilk-simd/compile/for2.c new file mode 100644 index 0000000..2d09ae8 --- /dev/null +++ b/gcc/testsuite/gcc.dg/cilk-plus/cilk-simd/compile/for2.c @@ -0,0 +1,66 @@ +/* { dg-do compile } */ +/* { dg-options "-O3 -std=c99 -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/cilk-simd/compile/for3.c b/gcc/testsuite/gcc.dg/cilk-plus/cilk-simd/compile/for3.c new file mode 100644 index 0000000..8660627 --- /dev/null +++ b/gcc/testsuite/gcc.dg/cilk-plus/cilk-simd/compile/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/tree-pretty-print.c b/gcc/tree-pretty-print.c index f3de68c..8d1f06e9 100644 --- a/gcc/tree-pretty-print.c +++ b/gcc/tree-pretty-print.c @@ -586,6 +586,17 @@ dump_omp_clause (pretty_printer *buffer, tree clause, int spc, int flags) pp_string (buffer, "taskgroup"); break; + case OMP_CLAUSE_CILK_ASSERT: + pp_string (buffer, "cilk_assert"); + break; + + case OMP_CLAUSE_CILK_VECTORLENGTH: + pp_string (buffer, "cilk_vectorlength("); + dump_generic_node (buffer, OMP_CLAUSE_CILK_VECTORLENGTH_EXPR (clause), + spc, flags, false); + pp_character (buffer, ')'); + break; + default: /* Should never happen. */ dump_generic_node (buffer, clause, spc, flags, false); diff --git a/gcc/tree.c b/gcc/tree.c index 36fadff..2bc6131 100644 --- a/gcc/tree.c +++ b/gcc/tree.c @@ -264,6 +264,8 @@ unsigned const char omp_clause_num_ops[] = 0, /* OMP_CLAUSE_PARALLEL */ 0, /* OMP_CLAUSE_SECTIONS */ 0 /* OMP_CLAUSE_TASKGROUP */ + , 0, /* OMP_CLAUSE_CILK_ASSERT */ + 1, /* OMP_CLAUSE_CILK_VECTORLENGTH */ }; const char * const omp_clause_code_name[] = @@ -305,6 +307,8 @@ const char * const omp_clause_code_name[] = "parallel", "sections", "taskgroup" + , "cilk_assert", + "cilk_vectorlength", }; @@ -10809,6 +10813,7 @@ walk_tree_1 (tree *tp, walk_tree_fn func, void *data, case OMP_CLAUSE_DIST_SCHEDULE: case OMP_CLAUSE_SAFELEN: case OMP_CLAUSE_SIMDLEN: + case OMP_CLAUSE_CILK_VECTORLENGTH: WALK_SUBTREE (OMP_CLAUSE_OPERAND (*tp, 0)); /* FALLTHRU */ @@ -10853,6 +10858,9 @@ walk_tree_1 (tree *tp, walk_tree_fn func, void *data, WALK_SUBTREE_TAIL (OMP_CLAUSE_CHAIN (*tp)); } + case OMP_CLAUSE_CILK_ASSERT: + break; + default: gcc_unreachable (); } diff --git a/gcc/tree.h b/gcc/tree.h index b4bd6c4..75fbebf 100644 --- a/gcc/tree.h +++ b/gcc/tree.h @@ -446,7 +446,13 @@ enum omp_clause_code OMP_CLAUSE_SECTIONS, /* OpenMP clause: taskgroup. */ - OMP_CLAUSE_TASKGROUP + OMP_CLAUSE_TASKGROUP, + + /* Cilk Plus clause: assert. */ + OMP_CLAUSE_CILK_ASSERT, + + /* Cilk Plus clause: vectorlength (constant-expression-list). */ + OMP_CLAUSE_CILK_VECTORLENGTH }; /* The definition of tree nodes fills the next several pages. */ @@ -1857,6 +1863,13 @@ extern void protected_set_expr_location (tree, location_t); OMP_CLAUSE_OPERAND (OMP_CLAUSE_RANGE_CHECK (OMP_CLAUSE_CHECK (NODE), \ OMP_CLAUSE_PRIVATE, \ OMP_CLAUSE_MAP), 0) + +/* In an OMP_SIMD_CLAUSE_CILK_VECTORLENGTH, one vectorlength + expression. */ +#define OMP_CLAUSE_CILK_VECTORLENGTH_EXPR(NODE) \ + OMP_CLAUSE_OPERAND (OMP_CLAUSE_SUBCODE_CHECK \ + (NODE, OMP_CLAUSE_CILK_VECTORLENGTH), 0) + #define OMP_CLAUSE_HAS_LOCATION(NODE) \ (LOCATION_LOCUS ((OMP_CLAUSE_CHECK (NODE))->omp_clause.locus) \ != UNKNOWN_LOCATION)