From patchwork Fri Nov 15 15:24:36 2013 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 8bit X-Patchwork-Submitter: Aldy Hernandez X-Patchwork-Id: 291600 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.2 with cipher ECDHE-RSA-AES256-GCM-SHA384 (256/256 bits)) (Client did not present a certificate) by ozlabs.org (Postfix) with ESMTPS id D44B62C009D for ; Sat, 16 Nov 2013 02:25:05 +1100 (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=eXBKjl08i6eZya8yy r7jy68ppYRld0R+yLbBd+ccAP82MDQvpRhlMGOI5dxwql4R2Bc37hWBQCoUQeqAH 43UcRUHRUdqmBKRtoruUKxVjuA9eyAwGkisgyPJ3XAEKB7pPt9fXEsxGHdywrpgk Eoj3+3/b3ecu60M0Z9dzB5rya8= 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=7yoo6Y5uZYpvxPFGtLMm9ua yhrs=; b=KnARwHLoCTHvuU+vyBg/NZl3UzR0b29vho4/u8F83KVNtHDKE2RvzB9 Ajxy+3Zrr0I6ZDKY/EZFL+XdBh4YA/X+30C8YaRhixQ4dyZem0UJQoBArPN8IaXm kugn09+byHY441Fe5RXgrpTXpowV/1VH/KK+PqtohBULhe1sF+jw= Received: (qmail 8283 invoked by alias); 15 Nov 2013 15:24:55 -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 8270 invoked by uid 89); 15 Nov 2013 15:24:54 -0000 Authentication-Results: sourceware.org; auth=none X-Virus-Found: No X-Spam-SWARE-Status: No, score=1.5 required=5.0 tests=AWL, BAYES_50, RDNS_NONE, SPF_HELO_PASS, SPF_PASS, URIBL_BLOCKED autolearn=no version=3.3.2 X-HELO: mx1.redhat.com Received: from Unknown (HELO mx1.redhat.com) (209.132.183.28) by sourceware.org (qpsmtpd/0.93/v0.84-503-g423c35a) with ESMTP; Fri, 15 Nov 2013 15:24:47 +0000 Received: from int-mx02.intmail.prod.int.phx2.redhat.com (int-mx02.intmail.prod.int.phx2.redhat.com [10.5.11.12]) by mx1.redhat.com (8.14.4/8.14.4) with ESMTP id rAFFOdl2028431 (version=TLSv1/SSLv3 cipher=DHE-RSA-AES256-SHA bits=256 verify=OK); Fri, 15 Nov 2013 10:24:39 -0500 Received: from reynosa.quesejoda.com (vpn-56-14.rdu2.redhat.com [10.10.56.14]) by int-mx02.intmail.prod.int.phx2.redhat.com (8.13.8/8.13.8) with ESMTP id rAFFOaaR001865; Fri, 15 Nov 2013 10:24:37 -0500 Message-ID: <52863CB4.50900@redhat.com> Date: Fri, 15 Nov 2013 08:24:36 -0700 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: Jakub Jelinek CC: Jason Merrill , gcc-patches , "Iyer, Balaji V" Subject: Re: PING: Fwd: Re: [patch] implement Cilk Plus simd loops on trunk References: <521B8ECA.70806@redhat.com> <521D060E.9030601@redhat.com> <524C95F2.1010802@redhat.com> <52618287.8010705@redhat.com> <52740D59.50104@redhat.com> <5284FF25.7020401@redhat.com> <20131114170553.GD27813@tucnak.zalov.cz> <52850AB6.2070408@redhat.com> <20131114180147.GE27813@tucnak.zalov.cz> <5285790E.9050000@redhat.com> <20131115073757.GA892@tucnak.redhat.com> In-Reply-To: <20131115073757.GA892@tucnak.redhat.com> On 11/15/13 00:37, Jakub Jelinek wrote: > On Thu, Nov 14, 2013 at 06:29:50PM -0700, Aldy Hernandez wrote: >>> Well, if you don't change anything in omp-low.c, then it wouldn't diagnose >>> setjmp call in #pragma simd, but given that also the OpenMP 4.0 spec >>> requires that #pragma omp simd doesn't contain calls to setjmp or longjmp >>> (ditto for #pragma omp declare simd functions), then scan_omp_1_stmt >>> should be changed to also call check_omp_nesting_restrictions for >>> setjmp/longjmp calls (the GIMPLE_CALL case then in >>> check_omp_nesting_restrictions can't assume all calls it sees are >>> BUILT_IN_NORMAL). >> >> Fixed in scan_omp_1_stmt. > > Well, setjmp_call_p is not just setjmp, but various other functions, > including getcontext, fork, vfork and many others, but it isn't longjmp. > I'd say we should just follow the spec and look solely for setjmp/longjmp, > for the others perhaps we can warn (though I think it isn't a big deal, > we are never going to vectorize those), but not error. Hmm, I thought we could error on all those other context changing functions, but you're right... error may be too big of a hammer. I have changed the patch to error on explicit setjmp/longjmp as well as the corresponding built-ins. > >>> Perhaps some bool is_cilkplus = false argument to >>> cp_parser_omp_clause_reduction would work for me (and for C too). >> >> Ok, I'm at a loss here, what parts of cp_parser_omp_clause_reduction >> are the user-defined reductions? I'm an OpenMP weenie. > > I guess it depends on what the Cilk+ spec says about reduction clause, > and from what I saw it is just too vague. > http://software.intel.com/sites/products/documentation/doclib/stdxe/2013/composerxe/compiler/cpp-win/index.htm#GUID-44B505B6-01AF-4865-8DF4-AF851F51DDA1.htm > just mentions > reduction(oper:var1 [,var2]…) oper is a reduction operator. > > So, the question is which reduction operators does it allow, for what > types, and what is the exact grammar for oper in that case. > > E.g. shall it only allow the +/-/*/&/&&/|/|| that OpenMP 2.5 had? > Or also min/max that OpenMP 3.1 added? > Shall it (for C++) allow stuff like reduction(operator +:var1) ? > And UDRs? Shall it allow something OpenMP doesn't allow? > > Depending to answer to those questions, the changes will differ. > E.g. if you only allow the OpenMP 2.5 stuff, then you'd fail in > cp_parser_omp_clause_reduction in > switch (cp_lexer_peek_token (parser->lexer)->type)'s > default: break; - default: if (is_cilkplus) goto resync_fail; break; > with some error message. If you want also min/max, you'd need > to add the fail after min/max recognition, but before recognition > of operator XYZ, if you want to allow even that, but not UDRs, > you'd fail before id = omp_reduction_id (code, id, NULL_TREE); if > code is still ERROR_MARK. > > Jakub > Looks like we need to wait on Intel to pontificate on whether UDRs are valid or not. Who knows...maybe no work at all! Woo hoo! How does this look? Aldy gcc/ChangeLog.pragmasimd * Makefile.in (C_COMMON_OBJS): Depend on c-cilkplus.o. * gimple-pretty-print.c (dump_omp_for): Add case for GF_OMP_FOR_KIND_CILKSIMD. * gimple.h (enum gf_mask): Restructure entries to add GF_OMP_FOR_KIND_CILKSIMD. * gimplify.c (is_gimple_stmt): Add case for CILK_SIMD. (gimplify_omp_for): Handle CILK_SIMD. (gimplify_expr): Add ccase for CILK_SIMD. * omp-low.c (extract_omp_for_data): Handle CILK_SIMD. (build_outer_var_ref): Same. (check_omp_nesting_restrictions): Same. (lower_rec_input_clauses): Same. (lower_lastprivate_clauses): Same. (expand_omp_for): Same. (execute_expand_omp): Check flag_enable_cilkplus. (execute_lower_omp): Same. (diagnose_sb_0): Handle CILK_SIMD. (diagnose_omp_structured_block_errors): Check flag_enable_cilkplus. (setjmp_or_longjmp_p): New. (scan_omp_1_stmt): Error on setjmp/longjmp in a simd construct. * tree-pretty-print.c (dump_generic_node): Add case for CILK_SIMD. * tree.def: Add tree code for CILK_SIMD. testsuite/ * c-c++-common/cilk-plus/PS: New directory. * g++.dg/cilk-plus/cilk-plus.exp: Run shared tests. * g++.dg/dg.exp: Run Cilk Plus tests. * gcc.dg/cilk-plus/cilk-plus.exp: Run shared tests. c-family/ * c-cilkplus.c: New file. * c-common.c (readonly_error): Add location argument. * c-common.h (readonly_error): Same. (c_finish_cilk_clauses): Protoize. (c_check_cilk_loop): Same. c-omp.c (c_finish_omp_for): Handle CILK_SIMD nodes. Do not fail on error_mark_node. Abstract increment canonicalization to here... (c_omp_for_incr_canonicalize_ptr): New. c-pragma.c (init_pragma): Register "simd" pragma. c-pragma.h (enum pragma_kind): Add PRAGMA_CILK_SIMD. (enum pragma_cilk_clause): New. c/ * c-parser.c (c_parser_cilk_simd): New. (c_parser_cilk_verify_simd): New. (c_parser_pragma): Add case for PRAGMA_CILK_SIMD. (c_parser_omp_for_loop): Add case for NE_EXPR. Set c_break_label for CILK_SIMD. (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-typeck.c (build_unary_op): Pass location argument to readonly_error. (build_modify_expr): Same. (build_asm_expr): Same. (c_finish_bc_stmt): Error on break/continue in loops. cp/ * Make-lang.in (CXX_AND_OBJCXX_OBJS): Depend on cp/cp-cilkplus.o. * cp-cilkplus.c: New file. * cp-tree.h (cpp_validate_cilk_plus_loop): Protoize. * parser.c (cp_parser_cilk_simd): New. (cp_debug_parser): Add case for IN_CILK_SIMD_FOR. (cp_parser_jump_statement): Same. (cp_parser_omp_for_cond): Add new argument. Add case for NE_EXPR. (cp_parser_omp_for_loop): Pass new argument to cp_parser_omp_for_cond. Handle CILK_SIMD nodes. Abstract initilization code to.. (cp_parser_omp_for_loop_init): ...here. (cp_parser_pragma): Add case for PRAGMA_CILK_SIMD. (cp_parser_cilk_simd_vectorlength): New. (cp_parser_cilk_simd_linear): New. (cp_parser_cilk_simd_clause_name): New. (cp_parser_cilk_simd_all_clauses): New. (cp_parser_cilk_simd): New. * parser.h (IN_CILK_SIMD_FOR): New macro. * pt.c (tsubst_expr): Add case for CILK_SIMD. * typeck2.c (cxx_readonly_error): Pass location argument to readonly_error. index 0000000..fa9c054 diff --git a/gcc/Makefile.in b/gcc/Makefile.in index 2987506..b2c0449 100644 --- a/gcc/Makefile.in +++ b/gcc/Makefile.in @@ -1138,6 +1138,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 \ + c-family/c-cilkplus.o \ c-family/array-notation-common.o c-family/cilk.o c-family/c-ubsan.o # Language-independent object files. diff --git a/gcc/c-family/c-cilkplus.c b/gcc/c-family/c-cilkplus.c new file mode 100644 index 0000000..6fa979d --- /dev/null +++ b/gcc/c-family/c-cilkplus.c @@ -0,0 +1,93 @@ +/* This file contains routines to construct and validate Cilk Plus + constructs within the C and C++ front ends. + + Copyright (C) 2013 Free Software Foundation, Inc. + Contributed by 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" + +/* Validate the body of a _Cilk_for construct or a <#pragma simd> for + loop. + + Returns true if there were no errors, false otherwise. */ + +bool +c_check_cilk_loop (location_t loc, tree decl) +{ + if (TREE_THIS_VOLATILE (decl)) + { + error_at (loc, "iteration variable cannot be volatile"); + return false; + } + return true; +} + +/* 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.c b/gcc/c-family/c-common.c index 1f5e4ed..7420a56 100644 --- a/gcc/c-family/c-common.c +++ b/gcc/c-family/c-common.c @@ -9815,7 +9815,7 @@ warn_for_omitted_condop (location_t location, tree cond) how ARG was being used. */ void -readonly_error (tree arg, enum lvalue_use use) +readonly_error (location_t loc, tree arg, enum lvalue_use use) { gcc_assert (use == lv_assign || use == lv_increment || use == lv_decrement || use == lv_asm); @@ -9828,59 +9828,59 @@ readonly_error (tree arg, enum lvalue_use use) if (TREE_CODE (arg) == COMPONENT_REF) { if (TYPE_READONLY (TREE_TYPE (TREE_OPERAND (arg, 0)))) - error (READONLY_MSG (G_("assignment of member " - "%qD in read-only object"), - G_("increment of member " - "%qD in read-only object"), - G_("decrement of member " - "%qD in read-only object"), - G_("member %qD in read-only object " - "used as % output")), - TREE_OPERAND (arg, 1)); + error_at (loc, READONLY_MSG (G_("assignment of member " + "%qD in read-only object"), + G_("increment of member " + "%qD in read-only object"), + G_("decrement of member " + "%qD in read-only object"), + G_("member %qD in read-only object " + "used as % output")), + TREE_OPERAND (arg, 1)); else - error (READONLY_MSG (G_("assignment of read-only member %qD"), - G_("increment of read-only member %qD"), - G_("decrement of read-only member %qD"), - G_("read-only member %qD used as % output")), - TREE_OPERAND (arg, 1)); + error_at (loc, READONLY_MSG (G_("assignment of read-only member %qD"), + G_("increment of read-only member %qD"), + G_("decrement of read-only member %qD"), + G_("read-only member %qD used as % output")), + TREE_OPERAND (arg, 1)); } else if (TREE_CODE (arg) == VAR_DECL) - error (READONLY_MSG (G_("assignment of read-only variable %qD"), - G_("increment of read-only variable %qD"), - G_("decrement of read-only variable %qD"), - G_("read-only variable %qD used as % output")), - arg); + error_at (loc, READONLY_MSG (G_("assignment of read-only variable %qD"), + G_("increment of read-only variable %qD"), + G_("decrement of read-only variable %qD"), + G_("read-only variable %qD used as % output")), + arg); else if (TREE_CODE (arg) == PARM_DECL) - error (READONLY_MSG (G_("assignment of read-only parameter %qD"), - G_("increment of read-only parameter %qD"), - G_("decrement of read-only parameter %qD"), - G_("read-only parameter %qD use as % output")), - arg); + error_at (loc, READONLY_MSG (G_("assignment of read-only parameter %qD"), + G_("increment of read-only parameter %qD"), + G_("decrement of read-only parameter %qD"), + G_("read-only parameter %qD use as % output")), + arg); else if (TREE_CODE (arg) == RESULT_DECL) { gcc_assert (c_dialect_cxx ()); - error (READONLY_MSG (G_("assignment of " - "read-only named return value %qD"), - G_("increment of " - "read-only named return value %qD"), - G_("decrement of " - "read-only named return value %qD"), - G_("read-only named return value %qD " - "used as %output")), - arg); + error_at (loc, READONLY_MSG (G_("assignment of " + "read-only named return value %qD"), + G_("increment of " + "read-only named return value %qD"), + G_("decrement of " + "read-only named return value %qD"), + G_("read-only named return value %qD " + "used as %output")), + arg); } else if (TREE_CODE (arg) == FUNCTION_DECL) - error (READONLY_MSG (G_("assignment of function %qD"), - G_("increment of function %qD"), - G_("decrement of function %qD"), - G_("function %qD used as % output")), - arg); + error_at (loc, READONLY_MSG (G_("assignment of function %qD"), + G_("increment of function %qD"), + G_("decrement of function %qD"), + G_("function %qD used as % output")), + arg); else - error (READONLY_MSG (G_("assignment of read-only location %qE"), - G_("increment of read-only location %qE"), - G_("decrement of read-only location %qE"), - G_("read-only location %qE used as % output")), - arg); + error_at (loc, READONLY_MSG (G_("assignment of read-only location %qE"), + G_("increment of read-only location %qE"), + G_("decrement of read-only location %qE"), + G_("read-only location %qE used as % output")), + arg); } /* Print an error message for an invalid lvalue. USE says diff --git a/gcc/c-family/c-common.h b/gcc/c-family/c-common.h index d9d2c44..b931fd6 100644 --- a/gcc/c-family/c-common.h +++ b/gcc/c-family/c-common.h @@ -970,7 +970,7 @@ enum lvalue_use { lv_asm }; -extern void readonly_error (tree, enum lvalue_use); +extern void readonly_error (location_t, tree, enum lvalue_use); extern void lvalue_error (location_t, enum lvalue_use); extern void invalid_indirection_error (location_t, tree, ref_operator); @@ -1289,6 +1289,11 @@ 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_clauses (tree); +extern tree c_validate_cilk_plus_loop (tree *, int *, void *); +extern bool c_check_cilk_loop (location_t, tree); + /* 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 b342bd2..921b406 100644 --- a/gcc/c-family/c-omp.c +++ b/gcc/c-family/c-omp.c @@ -349,6 +349,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. */ + +static 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 @@ -364,6 +386,10 @@ c_finish_omp_for (location_t locus, enum tree_code code, tree declv, bool fail = false; int i; + if (code == CILK_SIMD + && !c_check_cilk_loop (locus, TREE_VEC_ELT (declv, 0))) + fail = true; + gcc_assert (TREE_VEC_LENGTH (declv) == TREE_VEC_LENGTH (initv)); gcc_assert (TREE_VEC_LENGTH (declv) == TREE_VEC_LENGTH (condv)); gcc_assert (TREE_VEC_LENGTH (declv) == TREE_VEC_LENGTH (incrv)); @@ -407,8 +433,11 @@ c_finish_omp_for (location_t locus, enum tree_code code, tree declv, init, NULL_TREE); } - gcc_assert (TREE_CODE (init) == MODIFY_EXPR); - gcc_assert (TREE_OPERAND (init, 0) == decl); + if (init != error_mark_node) + { + gcc_assert (TREE_CODE (init) == MODIFY_EXPR); + gcc_assert (TREE_OPERAND (init, 0) == decl); + } if (cond == NULL_TREE) { @@ -487,7 +516,7 @@ c_finish_omp_for (location_t locus, enum tree_code code, tree declv, 0)) TREE_SET_CODE (cond, TREE_CODE (cond) == NE_EXPR ? LT_EXPR : GE_EXPR); - else + else if (code != CILK_SIMD) cond_ok = false; } } @@ -523,18 +552,7 @@ c_finish_omp_for (location_t locus, enum tree_code code, tree declv, 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 c75b087..029ab1e 100644 --- a/gcc/c-family/c-pragma.c +++ b/gcc/c-family/c-pragma.c @@ -1380,6 +1380,10 @@ init_pragma (void) omp_pragmas_simd[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 705bcb4..5379b9e 100644 --- a/gcc/c-family/c-pragma.h +++ b/gcc/c-family/c-pragma.h @@ -52,6 +52,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_IVDEP, @@ -103,6 +106,17 @@ 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_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 ffbf3c4..6f03402 100644 --- a/gcc/c/c-parser.c +++ b/gcc/c/c-parser.c @@ -1237,6 +1237,9 @@ 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_simd (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). @@ -9371,6 +9374,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 (parser); + return false; + default: if (id < PRAGMA_FIRST_EXTERNAL) { @@ -11543,6 +11553,10 @@ c_parser_omp_for_loop (location_t loc, c_parser *parser, enum tree_code code, case LT_EXPR: case LE_EXPR: break; + case NE_EXPR: + if (code == CILK_SIMD) + break; + /* FALLTHRU. */ default: /* Can't be cond = error_mark_node, because we want to preserve the location until c_finish_omp_for. */ @@ -11616,7 +11630,10 @@ c_parser_omp_for_loop (location_t loc, c_parser *parser, enum tree_code code, } save_break = c_break_label; - c_break_label = size_one_node; + if (code == CILK_SIMD) + c_break_label = build_int_cst (size_type_node, 2); + else + c_break_label = size_one_node; save_cont = c_cont_label; c_cont_label = NULL_TREE; body = push_stmt_list (); @@ -13311,7 +13328,252 @@ 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 (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) + && INTEGRAL_TYPE_P (TREE_TYPE (expr)) + && (TREE_CONSTANT (expr) + || DECL_P (expr))) + step = expr; + else + c_parser_error (parser, + "step size must be an integer constant " + "expression or an integer variable"); + } + 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); +} + +/* Main entry point for parsing Cilk Plus <#pragma simd> for + loops. */ +static void +c_parser_cilk_simd (c_parser *parser ATTRIBUTE_UNUSED) +{ + char p_name[100]; + strcpy (p_name, "#pragma omp"); + tree clauses = c_parser_cilk_all_clauses (parser); + tree block = c_begin_compound_stmt (true); + location_t loc = c_parser_peek_token (parser)->location; + c_parser_omp_for_loop (loc, parser, CILK_SIMD, clauses, NULL); + block = c_end_compound_stmt (loc, block, true); + add_stmt (block); +} + /* Parse a transaction attribute (GCC Extension). transaction-attribute: diff --git a/gcc/c/c-typeck.c b/gcc/c/c-typeck.c index 1cf9b45..eb3c0a9 100644 --- a/gcc/c/c-typeck.c +++ b/gcc/c/c-typeck.c @@ -4054,7 +4054,7 @@ build_unary_op (location_t location, /* Report a read-only lvalue. */ if (TYPE_READONLY (argtype)) { - readonly_error (arg, + readonly_error (location, arg, ((code == PREINCREMENT_EXPR || code == POSTINCREMENT_EXPR) ? lv_increment : lv_decrement)); @@ -5265,7 +5265,7 @@ build_modify_expr (location_t location, tree lhs, tree lhs_origtype, || TREE_CODE (lhstype) == UNION_TYPE) && C_TYPE_FIELDS_READONLY (lhstype))) { - readonly_error (lhs, lv_assign); + readonly_error (location, lhs, lv_assign); return error_mark_node; } else if (TREE_READONLY (lhs)) @@ -8948,7 +8948,7 @@ build_asm_expr (location_t loc, tree string, tree outputs, tree inputs, || ((TREE_CODE (TREE_TYPE (output)) == RECORD_TYPE || TREE_CODE (TREE_TYPE (output)) == UNION_TYPE) && C_TYPE_FIELDS_READONLY (TREE_TYPE (output))))) - readonly_error (output, lv_asm); + readonly_error (loc, output, lv_asm); constraint = TREE_STRING_POINTER (TREE_VALUE (TREE_PURPOSE (tail))); oconstraints[i] = constraint; @@ -9575,6 +9575,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 9bcea20..424f2e6 100644 --- a/gcc/cp/Make-lang.in +++ b/gcc/cp/Make-lang.in @@ -76,6 +76,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) diff --git a/gcc/cp/cp-cilkplus.c b/gcc/cp/cp-cilkplus.c new file mode 100644 index 0000000..5c1090a --- /dev/null +++ b/gcc/cp/cp-cilkplus.c @@ -0,0 +1,77 @@ +/* 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 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; + + 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 e30922a..4e26bd5 100644 --- a/gcc/cp/cp-tree.h +++ b/gcc/cp/cp-tree.h @@ -6177,6 +6177,9 @@ 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); + /* 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 eaad8e4..651c0db 100644 --- a/gcc/cp/parser.c +++ b/gcc/cp/parser.c @@ -233,6 +233,8 @@ static void cp_parser_initial_pragma static tree cp_literal_operator_id (const char *); +static void cp_parser_cilk_simd + (cp_parser *, cp_token *); static bool cp_parser_omp_declare_reduction_exprs (tree, cp_parser *); @@ -531,6 +533,8 @@ cp_debug_parser (FILE *file, cp_parser *parser) parser->in_statement & IN_SWITCH_STMT); cp_debug_print_flag (file, "Parsing a structured OpenMP block", parser->in_statement & IN_OMP_BLOCK); + cp_debug_print_flag (file, "Parsing a Cilk Plus for loop", + parser->in_statement & IN_CILK_SIMD_FOR); cp_debug_print_flag (file, "Parsing a an OpenMP loop", parser->in_statement & IN_OMP_FOR); cp_debug_print_flag (file, "Parsing an if statement", @@ -10558,6 +10562,9 @@ 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_SIMD_FOR: + error_at (token->location, "break statement used with Cilk Plus for loop"); + break; } cp_parser_require (parser, CPP_SEMICOLON, RT_SEMICOLON); break; @@ -10568,6 +10575,10 @@ cp_parser_jump_statement (cp_parser* parser) case 0: error_at (token->location, "continue statement not within a loop"); break; + case IN_CILK_SIMD_FOR: + error_at (token->location, + "continue statement within <#pragma simd> loop body"); + /* Fall through. */ case IN_ITERATION_STMT: case IN_OMP_FOR: statement = finish_continue_stmt (); @@ -28587,7 +28598,7 @@ cp_parser_omp_flush (cp_parser *parser, cp_token *pragma_tok) /* Helper function, to parse omp for increment expression. */ static tree -cp_parser_omp_for_cond (cp_parser *parser, tree decl) +cp_parser_omp_for_cond (cp_parser *parser, tree decl, enum tree_code code) { tree cond = cp_parser_binary_expression (parser, false, true, PREC_NOT_OPERATOR, NULL); @@ -28605,6 +28616,10 @@ cp_parser_omp_for_cond (cp_parser *parser, tree decl) case LT_EXPR: case LE_EXPR: break; + case NE_EXPR: + if (code == CILK_SIMD) + break; + /* Fall through: OpenMP disallows NE_EXPR. */ default: return error_mark_node; } @@ -28714,6 +28729,186 @@ cp_parser_omp_for_incr (cp_parser *parser, tree decl) return build2 (MODIFY_EXPR, TREE_TYPE (decl), decl, rhs); } +/* Parse the initialization statement of either an OpenMP for loop or + a Cilk Plus for loop. + + PARSING_OPENMP is true if parsing OpenMP, or false if parsing Cilk + Plus. + + Return true if the resulting construct should have an + OMP_CLAUSE_PRIVATE added to it. */ + +static bool +cp_parser_omp_for_loop_init (cp_parser *parser, + bool parsing_openmp, + tree &this_pre_body, + vec *for_block, + tree &init, + tree &decl, + tree &real_decl) +{ + if (cp_lexer_next_token_is (parser->lexer, CPP_SEMICOLON)) + return false; + + bool add_private_clause = false; + + /* 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)) + { + 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); + + 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); + } + } + } + return add_private_clause; +} + /* Parse the restricted form of the for statement allowed by OpenMP. */ static tree @@ -28759,157 +28954,13 @@ cp_parser_omp_for_loop (cp_parser *parser, enum tree_code code, tree clauses, 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; + add_private_clause + |= cp_parser_omp_for_loop_init (parser, + /*parsing_openmp=*/code != CILK_SIMD, + this_pre_body, for_block, + init, decl, real_decl); - 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); - } - } - } - } cp_parser_require (parser, CPP_SEMICOLON, RT_SEMICOLON); if (this_pre_body) { @@ -28998,7 +29049,7 @@ cp_parser_omp_for_loop (cp_parser *parser, enum tree_code code, tree clauses, cond = NULL; if (cp_lexer_next_token_is_not (parser->lexer, CPP_SEMICOLON)) - cond = cp_parser_omp_for_cond (parser, decl); + cond = cp_parser_omp_for_cond (parser, decl, code); cp_parser_require (parser, CPP_SEMICOLON, RT_SEMICOLON); incr = NULL; @@ -29068,7 +29119,10 @@ cp_parser_omp_for_loop (cp_parser *parser, enum tree_code code, tree clauses, /* Note that we saved the original contents of this flag when we entered the structured block, and so we don't need to re-save it here. */ - parser->in_statement = IN_OMP_FOR; + if (code == CILK_SIMD) + parser->in_statement = IN_CILK_SIMD_FOR; + else + parser->in_statement = IN_OMP_FOR; /* Note that the grammar doesn't call for a structured block here, though the loop as a whole is a structured block. */ @@ -31123,6 +31177,16 @@ cp_parser_pragma (cp_parser *parser, enum pragma_context context) return true; } + 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 (parser, pragma_tok); + return true; + default: gcc_assert (id >= PRAGMA_FIRST_EXTERNAL); c_invoke_pragma_handler (id); @@ -31188,6 +31252,255 @@ 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; + } + + bool saved_colon_corrects_to_scope_p = parser->colon_corrects_to_scope_p; + parser->colon_corrects_to_scope_p = false; + 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_assignment_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) + && INTEGRAL_TYPE_P (TREE_TYPE (e)) + && (TREE_CONSTANT (e) + || DECL_P (e))) + step_size = e; + else + cp_parser_error (parser, + "step size must be an integer constant " + "expression or an integer variable"); + } + + /* 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; + } + } + parser->colon_corrects_to_scope_p = saved_colon_corrects_to_scope_p; + 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 (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); + tree ret = cp_parser_omp_for_loop (parser, CILK_SIMD, clauses, NULL); + if (ret) + cpp_validate_cilk_plus_loop (OMP_FOR_BODY (ret)); + cp_parser_end_omp_structured_block (parser, save); + add_stmt (finish_omp_structured_block (sb)); + return; +} + /* Create an identifier for a generic parameter type (a synthesized template parameter implied by `auto' or a concept identifier). */ diff --git a/gcc/cp/parser.h b/gcc/cp/parser.h index 1024024..edd4e6e 100644 --- a/gcc/cp/parser.h +++ b/gcc/cp/parser.h @@ -300,6 +300,7 @@ typedef struct GTY(()) cp_parser { #define IN_OMP_BLOCK 4 #define IN_OMP_FOR 8 #define IN_IF_STMT 16 +#define IN_CILK_SIMD_FOR 32 unsigned char in_statement; /* TRUE if we are presently parsing the body of a switch statement. diff --git a/gcc/cp/pt.c b/gcc/cp/pt.c index 96a7db5..88215b7 100644 --- a/gcc/cp/pt.c +++ b/gcc/cp/pt.c @@ -13558,6 +13558,7 @@ tsubst_expr (tree t, tree args, tsubst_flags_t complain, tree in_decl, case OMP_FOR: case OMP_SIMD: + case CILK_SIMD: case OMP_DISTRIBUTE: { tree clauses, body, pre_body; diff --git a/gcc/cp/typeck2.c b/gcc/cp/typeck2.c index 9da8e3d..5c4fdfa 100644 --- a/gcc/cp/typeck2.c +++ b/gcc/cp/typeck2.c @@ -125,7 +125,7 @@ cxx_readonly_error (tree arg, enum lvalue_use errstring) "read-only reference %qD"), TREE_OPERAND (arg, 0)); else - readonly_error (arg, errstring); + readonly_error (input_location, arg, errstring); } diff --git a/gcc/gimple-pretty-print.c b/gcc/gimple-pretty-print.c index 86c2a55..a323698 100644 --- a/gcc/gimple-pretty-print.c +++ b/gcc/gimple-pretty-print.c @@ -1108,6 +1108,8 @@ 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"; case GF_OMP_FOR_KIND_DISTRIBUTE: kind = " distribute"; break; @@ -1139,6 +1141,9 @@ dump_gimple_omp_for (pretty_printer *buffer, gimple gs, int spc, int flags) case GF_OMP_FOR_KIND_SIMD: pp_string (buffer, "#pragma omp simd"); break; + case GF_OMP_FOR_KIND_CILKSIMD: + pp_string (buffer, "#pragma simd"); + break; case GF_OMP_FOR_KIND_DISTRIBUTE: pp_string (buffer, "#pragma omp distribute"); break; diff --git a/gcc/gimple.h b/gcc/gimple.h index 9ed3238..75ba9e9 100644 --- a/gcc/gimple.h +++ b/gcc/gimple.h @@ -102,10 +102,11 @@ enum gf_mask { GF_CALL_ALLOCA_FOR_VAR = 1 << 5, GF_CALL_INTERNAL = 1 << 6, GF_OMP_PARALLEL_COMBINED = 1 << 0, - GF_OMP_FOR_KIND_MASK = 3 << 0, + GF_OMP_FOR_KIND_MASK = 7, GF_OMP_FOR_KIND_FOR = 0 << 0, - GF_OMP_FOR_KIND_SIMD = 1 << 0, - GF_OMP_FOR_KIND_DISTRIBUTE = 2 << 0, + GF_OMP_FOR_KIND_SIMD = 2 << 0, + GF_OMP_FOR_KIND_CILKSIMD = 3 << 0, + GF_OMP_FOR_KIND_DISTRIBUTE = 1 << 2, GF_OMP_FOR_COMBINED = 1 << 2, GF_OMP_FOR_COMBINED_INTO = 1 << 3, GF_OMP_TARGET_KIND_MASK = 3 << 0, diff --git a/gcc/gimplify.c b/gcc/gimplify.c index 3253f86..8e74ae7 100644 --- a/gcc/gimplify.c +++ b/gcc/gimplify.c @@ -4198,6 +4198,7 @@ is_gimple_stmt (tree t) case OMP_PARALLEL: case OMP_FOR: case OMP_SIMD: + case CILK_SIMD: case OMP_DISTRIBUTE: case OMP_SECTIONS: case OMP_SECTION: @@ -6415,7 +6416,8 @@ gimplify_omp_for (tree *expr_p, gimple_seq *pre_p) orig_for_stmt = 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); @@ -6552,15 +6554,22 @@ gimplify_omp_for (tree *expr_p, gimple_seq *pre_p) { case PREINCREMENT_EXPR: case POSTINCREMENT_EXPR: - if (orig_for_stmt != for_stmt) + { + tree decl = TREE_OPERAND (t, 0); + // c_omp_for_incr_canonicalize_ptr() should have been + // called to massage things appropriately. + gcc_assert (!POINTER_TYPE_P (TREE_TYPE (decl))); + + if (orig_for_stmt != for_stmt) + break; + 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; - 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: @@ -6670,6 +6679,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; case OMP_DISTRIBUTE: kind = GF_OMP_FOR_KIND_DISTRIBUTE; break; default: gcc_unreachable (); @@ -7739,6 +7749,7 @@ gimplify_expr (tree *expr_p, gimple_seq *pre_p, gimple_seq *post_p, case OMP_FOR: case OMP_SIMD: + case CILK_SIMD: case OMP_DISTRIBUTE: ret = gimplify_omp_for (expr_p, pre_p); break; diff --git a/gcc/omp-low.c b/gcc/omp-low.c index 86f95a1..1f8c168 100644 --- a/gcc/omp-low.c +++ b/gcc/omp-low.c @@ -283,7 +283,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; bool distribute = gimple_omp_for_kind (for_stmt) == GF_OMP_FOR_KIND_DISTRIBUTE; @@ -375,6 +375,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); @@ -1001,7 +1005,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. */ @@ -2228,7 +2232,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"); @@ -2251,7 +2255,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; if (gimple_omp_for_kind (stmt) == GF_OMP_FOR_KIND_DISTRIBUTE) { @@ -2534,6 +2538,23 @@ scan_omp_1_op (tree *tp, int *walk_subtrees, void *data) return NULL_TREE; } +/* Return true if FNDECL is a setjmp or a longjmp. */ + +static bool +setjmp_or_longjmp_p (const_tree fndecl) +{ + if (DECL_BUILT_IN_CLASS (fndecl) == BUILT_IN_NORMAL + && (DECL_FUNCTION_CODE (fndecl) == BUILT_IN_SETJMP + || DECL_FUNCTION_CODE (fndecl) == BUILT_IN_LONGJMP)) + return true; + + tree declname = DECL_NAME (fndecl); + if (!declname) + return false; + const char *name = IDENTIFIER_POINTER (declname); + return !strcmp (name, "setjmp") || !strcmp (name, "longjmp"); +} + /* Helper function for scan_omp. @@ -2557,22 +2578,33 @@ scan_omp_1_stmt (gimple_stmt_iterator *gsi, bool *handled_ops_p, else if (is_gimple_call (stmt)) { tree fndecl = gimple_call_fndecl (stmt); - if (fndecl - && DECL_BUILT_IN_CLASS (fndecl) == BUILT_IN_NORMAL) - switch (DECL_FUNCTION_CODE (fndecl)) - { - case BUILT_IN_GOMP_BARRIER: - case BUILT_IN_GOMP_CANCEL: - case BUILT_IN_GOMP_CANCELLATION_POINT: - case BUILT_IN_GOMP_TASKYIELD: - case BUILT_IN_GOMP_TASKWAIT: - case BUILT_IN_GOMP_TASKGROUP_START: - case BUILT_IN_GOMP_TASKGROUP_END: - remove = !check_omp_nesting_restrictions (stmt, ctx); - break; - default: - break; - } + if (fndecl) + { + if (setjmp_or_longjmp_p (fndecl) + && ctx + && gimple_code (ctx->stmt) == GIMPLE_OMP_FOR + && gimple_omp_for_kind (ctx->stmt) & GF_OMP_FOR_KIND_SIMD) + { + remove = true; + error_at (gimple_location (stmt), + "setjmp/longjmp inside simd construct"); + } + else if (DECL_BUILT_IN_CLASS (fndecl) == BUILT_IN_NORMAL) + switch (DECL_FUNCTION_CODE (fndecl)) + { + case BUILT_IN_GOMP_BARRIER: + case BUILT_IN_GOMP_CANCEL: + case BUILT_IN_GOMP_CANCELLATION_POINT: + case BUILT_IN_GOMP_TASKYIELD: + case BUILT_IN_GOMP_TASKWAIT: + case BUILT_IN_GOMP_TASKGROUP_START: + case BUILT_IN_GOMP_TASKGROUP_END: + remove = !check_omp_nesting_restrictions (stmt, ctx); + break; + default: + break; + } + } } if (remove) { @@ -2965,7 +2997,7 @@ lower_rec_input_clauses (tree clauses, gimple_seq *ilist, gimple_seq *dlist, bool reduction_omp_orig_ref = 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; @@ -3585,7 +3617,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) gimple_seq_add_stmt (ilist, build_omp_barrier (NULL_TREE)); } @@ -3664,7 +3696,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) @@ -3759,7 +3791,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 @@ -6792,7 +6824,7 @@ expand_omp_for (struct omp_region *region, gimple inner_stmt) 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) @@ -8234,7 +8266,8 @@ execute_expand_omp (void) static bool gate_expand_omp (void) { - return ((flag_openmp != 0 || flag_openmp_simd != 0) && !seen_error ()); + return ((flag_openmp != 0 || flag_openmp_simd != 0 + || flag_enable_cilkplus != 0) && !seen_error ()); } namespace { @@ -10055,7 +10088,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 && flag_openmp_simd == 0) + if (flag_openmp == 0 && flag_openmp_simd == 0 && flag_enable_cilkplus == 0) return 0; all_contexts = splay_tree_new (splay_tree_compare_pointers, 0, @@ -10175,12 +10208,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; @@ -10484,7 +10538,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..9b10041 --- /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 "setjmp" } */ + a[i] = b[i]; + } + +#pragma simd + for (int i=0; i < 1000; ++i) + { + if (c==5) + break; /* { dg-error "break statement " } */ + } + +#pragma simd + for (int i=0; i < 1000; ++i) + { +#pragma omp for /* { dg-error "OpenMP constructs may not" } */ + 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..27d117e --- /dev/null +++ b/gcc/testsuite/c-c++-common/cilk-plus/PS/clauses1.c @@ -0,0 +1,80 @@ +/* { 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]; + +#pragma simd linear(j : k) + for (int i=0; i < 1234; ++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..3b67895 --- /dev/null +++ b/gcc/testsuite/c-c++-common/cilk-plus/PS/for1.c @@ -0,0 +1,132 @@ +/* { dg-do compile } */ +/* { dg-options "-O3 -fcilkplus" } */ + +int *a, *b, *c; +int something; + +void foo() +{ + int i, j; + + // Declaration and initialization is allowed. +#pragma simd + for (int i=0; i < 1000; i++) + a[i] = b[j]; + + // Empty initialization is not allowed. +#pragma simd + for (; i < 5; ++i) // { dg-error "expected iteration" } + a[i] = i; + + // Empty condition is not allowed. +#pragma simd + for (int i=0; ; ++i) /* { dg-error "missing controlling" } */ + 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 "invalid controlling\|invalid type for iteration\|invalid increment" } */ + a[ss.i] = b[ss.i]; + + #pragma simd + for (float f=0.0; f < 15.0; ++f) /* { dg-error "invalid type" } */ + 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]; + +#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/for2.c b/gcc/testsuite/c-c++-common/cilk-plus/PS/for2.c new file mode 100644 index 0000000..8660627 --- /dev/null +++ b/gcc/testsuite/c-c++-common/cilk-plus/PS/for2.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/for3.c b/gcc/testsuite/c-c++-common/cilk-plus/PS/for3.c new file mode 100644 index 0000000..2da8235 --- /dev/null +++ b/gcc/testsuite/c-c++-common/cilk-plus/PS/for3.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/reduction-1.c b/gcc/testsuite/c-c++-common/cilk-plus/PS/reduction-1.c new file mode 100644 index 0000000..d8cec84 --- /dev/null +++ b/gcc/testsuite/c-c++-common/cilk-plus/PS/reduction-1.c @@ -0,0 +1,38 @@ +/* { dg-do run } */ +/* { 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..f5554f6 --- /dev/null +++ b/gcc/testsuite/c-c++-common/cilk-plus/PS/reduction-2.c @@ -0,0 +1,36 @@ +/* { dg-do run } */ +/* { 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; + return 1; +} 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..26822d6 --- /dev/null +++ b/gcc/testsuite/c-c++-common/cilk-plus/PS/reduction-3.c @@ -0,0 +1,43 @@ +/* { dg-do run } */ +/* { 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..6e16cfc --- /dev/null +++ b/gcc/testsuite/g++.dg/cilk-plus/for.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 "before 'static'\|not declared\|expected" } */ + a[tt] = b[tt]; + +#pragma simd + for (extern int var=0; var < 1000; ++var) /* { dg-error "before 'extern'\|not declared\|expected" } */ + a[var] = var; + +#pragma simd + for (register int regj = 0; regj < 1000; ++regj) /* { dg-error "before 'register'\|not declared\|expected" } */ + b[regj] = a[regj] * 2; + +#pragma simd + for (volatile int vj=0; vj<1000; ++vj) /* { dg-error "iteration variable cannot be volatile" } */ + a[vj] = b[vj]; +} 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..345e542 --- /dev/null +++ b/gcc/testsuite/g++.dg/cilk-plus/for2.C @@ -0,0 +1,43 @@ +/* { dg-do compile } */ +/* { dg-options "-fcilkplus" } */ + +int *p; +extern int stuff(); + +template +void foobar(int a) +{ +#pragma simd + for (int i=0; i < a; ++i) + p[i] = value; +} + +template +void foobar2(int a) +{ + int j = 123; +#pragma simd linear(j : value) + for (int i=0; i < a; ++i) + { + p[i] = value; + j += stuff(); + } +} + +void funky() +{ + foobar <69> (1000); + foobar2 <123> (2000); +} + +void foobar3(int a) +{ + int j = 123; +#pragma simd linear(j : a + a) /* { dg-error "step size must be an integer" } */ + for (int i=0; i < a; ++i) + { + p[i] = 1234; + extern int bar(); + j += bar(); + } +} diff --git a/gcc/testsuite/g++.dg/cilk-plus/for3.C b/gcc/testsuite/g++.dg/cilk-plus/for3.C new file mode 100644 index 0000000..28dbdee --- /dev/null +++ b/gcc/testsuite/g++.dg/cilk-plus/for3.C @@ -0,0 +1,18 @@ +/* { 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 (int tt=5; tt < 10; ++tt) + { + a[tt] = b[tt]; + if (tt == 8) + throw 1; /* { dg-error "throw expressions are not allowed" } */ + } +} diff --git a/gcc/testsuite/g++.dg/dg.exp b/gcc/testsuite/g++.dg/dg.exp index 0528538..d107dfe 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/cilk-plus.exp b/gcc/testsuite/gcc.dg/cilk-plus/cilk-plus.exp index 7dc2c6e..7407e8e 100644 --- a/gcc/testsuite/gcc.dg/cilk-plus/cilk-plus.exp +++ b/gcc/testsuite/gcc.dg/cilk-plus/cilk-plus.exp @@ -33,6 +33,13 @@ set ALWAYS_CFLAGS "" lappend ALWAYS_CFLAGS "-L${library_var}/libcilkrts/.libs" 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]] " -O1 -fcilkplus" " " dg-runtest [lsort [glob -nocomplain $srcdir/c-c++-common/cilk-plus/AN/*.c]] " -O2 -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..285f35a --- /dev/null +++ b/gcc/testsuite/gcc.dg/cilk-plus/for2.c @@ -0,0 +1,11 @@ +/* { dg-do compile } */ +/* { dg-options "-O3 -fcilkplus" } */ + +int *a, *b; + +void foo() +{ +#pragma simd + for (const int ci=0; ci<1000; ++ci) /* { dg-error "increment of read-only var\|invalid controlling\|invalid increment\|assignment of read" } */ + 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 7cd578c..7fe849d 100644 --- a/gcc/tree-pretty-print.c +++ b/gcc/tree-pretty-print.c @@ -2380,6 +2380,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; + case OMP_DISTRIBUTE: pp_string (buffer, "#pragma omp distribute"); goto dump_omp_loop; diff --git a/gcc/tree.def b/gcc/tree.def index 6763e78..8eecba7 100644 --- a/gcc/tree.def +++ b/gcc/tree.def @@ -1042,6 +1042,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 distribute [clause1 ... clauseN] Operands like for OMP_FOR. */ DEFTREECODE (OMP_DISTRIBUTE, "omp_distribute", tcc_statement, 6)