From patchwork Fri Nov 15 21:44:45 2013 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: Aldy Hernandez X-Patchwork-Id: 291704 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 166B62C00BB for ; Sat, 16 Nov 2013 08:45:13 +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=WHZY5YPM9MvkRJ57A UKt9+6lh3RYYmi1xLQWZe7z2wb29ZYxbhoFZQ0pHuowBCDS1Xg17GnLAoDkxlWBN 1X5+/o9uYwGCd+c1UwMtvQ/QeuU6H6tnrYophXmvA644HAal0XhoMLfslK5Wosji bdYh+mgHg9gFGOB/bgV8iq2bqc= 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=qkt9yWEGshD6/iF8CvNfjEX mDNk=; b=GtgAOmejuoVw4tOdwnUy2m6lKQto1hMs0PNMaI4tR8AjNdJfAFvYkmP 8o8c1tbnyzUkJthlt1dF0t2ppoXh6vP6X4FLOldYztrC6Fh4z76qbW3ZFx1EBN60 7IQx8mUEScvbreoz3S2Kw2rCkSKc1eqK1WCucmenRgozJU7mMdyw= Received: (qmail 20736 invoked by alias); 15 Nov 2013 21:45:03 -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 20700 invoked by uid 89); 15 Nov 2013 21:45:02 -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 21:44:55 +0000 Received: from int-mx10.intmail.prod.int.phx2.redhat.com (int-mx10.intmail.prod.int.phx2.redhat.com [10.5.11.23]) by mx1.redhat.com (8.14.4/8.14.4) with ESMTP id rAFLimTC025753 (version=TLSv1/SSLv3 cipher=DHE-RSA-AES256-SHA bits=256 verify=OK); Fri, 15 Nov 2013 16:44:48 -0500 Received: from reynosa.quesejoda.com (vpn-56-14.rdu2.redhat.com [10.10.56.14]) by int-mx10.intmail.prod.int.phx2.redhat.com (8.14.4/8.14.4) with ESMTP id rAFLijov020630; Fri, 15 Nov 2013 16:44:46 -0500 Message-ID: <528695CD.5080705@redhat.com> Date: Fri, 15 Nov 2013 14:44:45 -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> <52863CB4.50900@redhat.com> In-Reply-To: <52863CB4.50900@redhat.com> I fixed a few nits Jason pointed out off-line, and both him and Jakub have approved the patch for trunk. In running the final round of tests I noticed a few problems with my choice of bit numbers for the GF_OMP_* masks. I fixed them, and re-ran tests on x86-64 Linux. Attached is the final version of the patch I have committed to trunk. Thanks folks. Aldy commit c35bbe034cedaabf5f82b1af53a0a5e5560a2133 Author: Aldy Hernandez Date: Mon Oct 14 18:32:13 2013 -0500 * 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. diff --git a/gcc/Makefile.in b/gcc/Makefile.in index 806b6ca..77fba80 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 7955bb1..d7d5cb2 100644 --- a/gcc/c-family/c-common.c +++ b/gcc/c-family/c-common.c @@ -9816,7 +9816,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); @@ -9829,59 +9829,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 a9c9e6e..a823f14 100644 --- a/gcc/c/c-typeck.c +++ b/gcc/c/c-typeck.c @@ -4055,7 +4055,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)); @@ -5266,7 +5266,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)) @@ -8949,7 +8949,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; @@ -9576,6 +9576,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 ab33257..27f1054 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 (); @@ -28591,7 +28602,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); @@ -28609,6 +28620,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; } @@ -28718,6 +28733,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 @@ -28763,157 +28958,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) { @@ -29002,7 +29053,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; @@ -29072,7 +29123,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. */ @@ -31127,6 +31181,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); @@ -31192,6 +31256,257 @@ 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 (type_dependent_expression_p (e) + || value_dependent_expression_p (e) + || (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 e714e79..3bc8ccb 100644 --- a/gcc/cp/pt.c +++ b/gcc/cp/pt.c @@ -13566,6 +13566,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 26d59d1..b20d11a 100644 --- a/gcc/gimple-pretty-print.c +++ b/gcc/gimple-pretty-print.c @@ -1118,6 +1118,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; @@ -1149,6 +1151,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 6a0c39b..c7cb9f7 100644 --- a/gcc/gimple.h +++ b/gcc/gimple.h @@ -102,12 +102,13 @@ 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_COMBINED = 1 << 2, - GF_OMP_FOR_COMBINED_INTO = 1 << 3, + 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 << 3, + GF_OMP_FOR_COMBINED_INTO = 1 << 4, GF_OMP_TARGET_KIND_MASK = 3 << 0, GF_OMP_TARGET_KIND_REGION = 0 << 0, GF_OMP_TARGET_KIND_DATA = 1 << 0, diff --git a/gcc/gimplify.c b/gcc/gimplify.c index 4e6f448..bb50e25 100644 --- a/gcc/gimplify.c +++ b/gcc/gimplify.c @@ -4189,6 +4189,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: @@ -6406,7 +6407,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); @@ -6543,15 +6545,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: @@ -6661,6 +6670,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 (); @@ -7730,6 +7740,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 5be9ff8..e2fc53c 100644 --- a/gcc/omp-low.c +++ b/gcc/omp-low.c @@ -285,7 +285,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; @@ -377,6 +377,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); @@ -1003,7 +1007,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. */ @@ -2230,7 +2234,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"); @@ -2253,7 +2257,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) { @@ -2536,6 +2540,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. @@ -2559,22 +2580,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) { @@ -2967,7 +2999,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; @@ -3587,7 +3619,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)); } @@ -3666,7 +3698,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) @@ -3761,7 +3793,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 @@ -6794,7 +6826,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) @@ -8236,7 +8268,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 { @@ -10057,7 +10090,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, @@ -10177,12 +10210,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; @@ -10486,7 +10540,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/cilk-plus/for4.C b/gcc/testsuite/g++.dg/cilk-plus/for4.C new file mode 100644 index 0000000..5b86b9f --- /dev/null +++ b/gcc/testsuite/g++.dg/cilk-plus/for4.C @@ -0,0 +1,22 @@ +/* { dg-do compile } */ +/* { dg-options "-fcilkplus" } */ + +int *p; +extern int stuff(); + +template +void foobar(int a) +{ + int j = 123; +#pragma simd linear(j : value + 1) + for (int i=0; i < a; ++i) + { + p[i] = value; + j += stuff(); + } +} + +void funky() +{ + foobar <69> (1000); +} 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)