From patchwork Sat Jul 6 18:46:59 2013 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: Jakub Jelinek X-Patchwork-Id: 257297 Return-Path: X-Original-To: incoming@patchwork.ozlabs.org Delivered-To: patchwork-incoming@bilbo.ozlabs.org Received: from sourceware.org (server1.sourceware.org [209.132.180.131]) (using TLSv1 with cipher DHE-RSA-AES256-SHA (256/256 bits)) (Client CN "localhost", Issuer "www.qmailtoaster.com" (not verified)) by ozlabs.org (Postfix) with ESMTPS id 79DE52C0084 for ; Sun, 7 Jul 2013 04:47:20 +1000 (EST) DomainKey-Signature: a=rsa-sha1; c=nofws; d=gcc.gnu.org; h=list-id :list-unsubscribe:list-archive:list-post:list-help:sender:date :from:to:cc:subject:message-id:reply-to:mime-version :content-type; q=dns; s=default; b=NVWKh6OIxDiIv5AWPSloV2S1K6Mkx GIFfav2dhXAqL/3DF7uRfdFWWYpWgTy7kCt8tEFDgiKxUhzXyWSw5hGoIoketDTL rEaa6q6tWYHmlvdWtrTwDZVyZZ13EQpw6tr7ulFKqlfdZl23ZHeU1c2W5GpZKDnT kRFv0hcK08+uGk= 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:date :from:to:cc:subject:message-id:reply-to:mime-version :content-type; s=default; bh=FGaIbKuAAQxcN99mFRUr3GtRntk=; b=L4K u13n0UtvSQexInhI85SJ+O1aTW8y2PizAOtDF/NgNSkxvhJa+u4A15KaD5HN5s28 pB+25GvsUGDIpmCWAV9qlTmatRwGPnwvnhaXmLPAq8baWQYF8TR9SusJZQu1+0xs v4BsiFgBrSwFAcJIHW5PwQLr8dFCHmHSxKCx1hGs= Received: (qmail 11522 invoked by alias); 6 Jul 2013 18:47:11 -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 11512 invoked by uid 89); 6 Jul 2013 18:47:11 -0000 X-Spam-SWARE-Status: No, score=-6.1 required=5.0 tests=AWL, BAYES_00, RCVD_IN_HOSTKARMA_W, RCVD_IN_HOSTKARMA_WL, RP_MATCHES_RCVD, SPF_HELO_PASS, SPF_PASS, TW_AV, TW_BJ, TW_CP, TW_TM autolearn=no version=3.3.1 Received: from mx1.redhat.com (HELO mx1.redhat.com) (209.132.183.28) by sourceware.org (qpsmtpd/0.84/v0.84-167-ge50287c) with ESMTP; Sat, 06 Jul 2013 18:47:07 +0000 Received: from int-mx12.intmail.prod.int.phx2.redhat.com (int-mx12.intmail.prod.int.phx2.redhat.com [10.5.11.25]) by mx1.redhat.com (8.14.4/8.14.4) with ESMTP id r66Il4CX000862 (version=TLSv1/SSLv3 cipher=DHE-RSA-AES256-SHA bits=256 verify=OK); Sat, 6 Jul 2013 14:47:04 -0400 Received: from zalov.cz (vpn1-6-162.ams2.redhat.com [10.36.6.162]) by int-mx12.intmail.prod.int.phx2.redhat.com (8.14.4/8.14.4) with ESMTP id r66Il15t016387 (version=TLSv1/SSLv3 cipher=DHE-RSA-AES256-SHA bits=256 verify=NO); Sat, 6 Jul 2013 14:47:02 -0400 Received: from zalov.cz (localhost [127.0.0.1]) by zalov.cz (8.14.5/8.14.5) with ESMTP id r66Il0Xj008610; Sat, 6 Jul 2013 20:47:00 +0200 Received: (from jakub@localhost) by zalov.cz (8.14.5/8.14.5/Submit) id r66IkxAS008609; Sat, 6 Jul 2013 20:46:59 +0200 Date: Sat, 6 Jul 2013 20:46:59 +0200 From: Jakub Jelinek To: Richard Henderson , "Joseph S. Myers" Cc: gcc-patches@gcc.gnu.org Subject: [gomp4] Bring C FE again to feature parity with C++ FE OpenMP 4.0 handling Message-ID: <20130706184659.GH2336@tucnak.redhat.com> Reply-To: Jakub Jelinek MIME-Version: 1.0 Content-Disposition: inline User-Agent: Mutt/1.5.21 (2010-09-15) Hi! This patch syncs another almost two months of C++ FE only changes to the C FE. Regtested on x86_64-linux, committed to gomp-4_0-branch. 2013-07-06 Jakub Jelinek gcc/c/ * c-lang.h (current_omp_declare_target_attribute): New extern decl. * Make-lang.in (c/c-parser.o): Depend on c/c-lang.h. * c-parser.c: Include c-lang.h. (c_parser_pragma): Handle PRAGMA_OMP_TARGET and PRAGMA_OMP_END_DECLARE_TARGET. (c_parser_omp_clause_name): Handle thread_limit clause. (c_parser_omp_variable_list): Parse array sections for OMP_CLAUSE_{DEPEND,MAP,TO,FROM} clauses. (c_parser_omp_clause_reduction): Remove declare_simd argument. Pass false instead of declare_simd to c_parser_omp_variable_list. (c_parser_omp_clause_cancelkind): Remove diagnostics. (c_parser_omp_clause_thread_limit): New function. (c_parser_omp_all_clauses): Add finish_p argument. Don't call c_finish_omp_clauses if it is false. Require that OMP_CLAUSE_{PARALLEL,FOR,SECTIONS,TASKGROUP} must be first in the list of clauses. Adjust c_parser_omp_clause_reduction caller. (c_parser_omp_for_loop): Change last argument to cclauses, and adjust uses to grab parallel clauses from the array of all the split clauses. (omp_split_clauses): New function. (c_parser_omp_simd): Add p_name, mask and cclauses arguments. Allow the function to be called also when parsing combined constructs. (c_parser_omp_sections): Likewise. (c_parser_omp_for): Add p_name, mask and cclauses arguments. Allow the function to be called also when parsing combined constructs, and call cp_parser_omp_simd when parsing for simd. (c_parser_omp_parallel): Likewise. (c_parser_omp_single, c_parser_omp_task, c_parser_omp_cancel, c_parser_omp_cancellation_point, c_parser_omp_declare_simd): Adjust c_parser_omp_all_clauses callers. (OMP_TEAMS_CLAUSE_MASK, OMP_TARGET_CLAUSE_MASK, OMP_TARGET_DATA_CLAUSE_MASK, OMP_TARGET_UPDATE_CLAUSE_MASK, OMP_DISTRIBUTE_CLAUSE_MASK): Define. (c_parser_omp_teams, c_parser_omp_target, c_parser_omp_target_data, c_parser_omp_target_update, c_parser_omp_distribute): New functions. (c_parser_omp_construct): Handle PRAGMA_OMP_DISTRIBUTE and PRAGMA_OMP_TEAMS. Adjust callers of c_parser_omp_simd, c_parser_omp_sections, c_parser_omp_for and c_parser_omp_parallel. (OMP_DECLARE_SIMD_CLAUSE_MASK): Remove OMP_CLAUSE_REDUCTION. (c_parser_omp_declare_target, c_parser_omp_end_declare_target): New functions. (c_parser_omp_declare): For target keyword call c_parser_omp_declare_target. Adjust expected keyword diagnostics. * c-decl.c (current_omp_declare_target_attribute): New variable. (c_decl_attributes): New function. (start_decl, start_function): Use it instead of decl_attributes. * c-typeck.c (handle_omp_array_sections_1, handle_omp_array_sections): New functions. (c_finish_omp_clauses): Handle array sections on OMP_CLAUSE_{MAP,TO,FROM,DEPEND}. If not array sections, mark the decl addressable. Complain if OMP_CLAUSE_{MAP,TO,FROM} decls or array sections don't have complete type. Handle OMP_CLAUSE_THREAD_LIMIT. gcc/cp/ * parser.c (cp_parser_omp_end_declare_target): Diagnose if #pragma omp end isn't followed by declare target. (cp_parser_omp_declare): Adjust expected keyword diagnostics. gcc/testsuite/ * c-c++-common/gomp/depend-1.c: Enable for C as well. * c-c++-common/gomp/depend-2.c: Likewise. * c-c++-common/gomp/map-1.c: Likewise. gcc/c-family/ * c-pragma.h (enum pragma_kind): Remove PRAGMA_OMP_DECLARE_SIMD, PRAGMA_OMP_DECLARE_TARGET, PRAGMA_OMP_DISTRIBUTE_PARALLEL_FOR, PRAGMA_OMP_DISTRIBUTE_PARALLEL_FOR_SIMD, PRAGMA_OMP_DISTRIBUTE_SIMD, PRAGMA_OMP_FOR_SIMD, PRAGMA_OMP_PARALLEL_FOR, PRAGMA_OMP_PARALLEL_FOR_SIMD, PRAGMA_OMP_PARALLEL_SECTIONS, PRAGMA_OMP_TARGET_DATA, PRAGMA_OMP_TARGET_TEAMS, PRAGMA_OMP_TARGET_TEAMS_DISTRIBUTE, PRAGMA_OMP_TARGET_TEAMS_DISTRIBUTE_PARALLEL_FOR, PRAGMA_OMP_TARGET_TEAMS_DISTRIBUTE_PARALLEL_FOR_SIMD, PRAGMA_OMP_TARGET_UPDATE, PRAGMA_OMP_TEAMS_DISTRIBUTE, PRAGMA_OMP_TEAMS_DISTRIBUTE_PARALLEL_FOR and PRAGMA_OMP_TEAMS_DISTRIBUTE_PARALLEL_FOR_SIMD. libgomp/ * testsuite/libgomp.c/for-3.c: New test. * testsuite/libgomp.c/simd-1.c: New test. * testsuite/libgomp.c/simd-2.c: New test. * testsuite/libgomp.c/simd-3.c: New test. Jakub --- gcc/c/c-lang.h.jj 2013-03-20 10:04:58.000000000 +0100 +++ gcc/c/c-lang.h 2013-07-06 17:29:09.733747004 +0200 @@ -55,5 +55,8 @@ struct GTY(()) language_function { int warn_about_return_type; }; +/* If non-zero, implicit "omp declare target" attribute is added into the + attribute lists. */ +extern GTY(()) int current_omp_declare_target_attribute; #endif /* ! GCC_C_LANG_H */ --- gcc/c/Make-lang.in.jj 2013-06-26 12:13:51.000000000 +0200 +++ gcc/c/Make-lang.in 2013-07-06 17:31:02.763880113 +0200 @@ -181,8 +181,8 @@ c/c-objc-common.o : c/c-objc-common.c c/ $(TREE_PRETTY_PRINT_H) c/c-parser.o : c/c-parser.c $(CONFIG_H) $(SYSTEM_H) coretypes.h \ - $(TM_H) $(TREE_H) $(C_TREE_H) $(C_COMMON_H) $(C_PRAGMA_H) $(CPPLIB_H) \ - $(GGC_H) $(TIMEVAR_H) $(INPUT_H) $(FLAGS_H) \ + $(TM_H) $(TREE_H) c/c-lang.h $(C_TREE_H) $(C_COMMON_H) $(C_PRAGMA_H) \ + $(CPPLIB_H) $(GGC_H) $(TIMEVAR_H) $(INPUT_H) $(FLAGS_H) \ gt-c-c-parser.h langhooks.h \ $(VEC_H) $(TARGET_H) $(CGRAPH_H) $(PLUGIN_H) \ c-family/c-objc.h --- gcc/c/c-parser.c.jj 2013-07-03 22:15:07.000000000 +0200 +++ gcc/c/c-parser.c 2013-07-06 19:59:14.729863508 +0200 @@ -46,6 +46,7 @@ along with GCC; see the file COPYING3. #include "timevar.h" #include "c-family/c-pragma.h" #include "c-tree.h" +#include "c-lang.h" #include "flags.h" #include "ggc.h" #include "c-family/c-common.h" @@ -1192,6 +1193,8 @@ static void c_parser_omp_cancellation_po enum pragma_context { pragma_external, pragma_struct, pragma_param, pragma_stmt, pragma_compound }; static bool c_parser_pragma (c_parser *, enum pragma_context); +static bool c_parser_omp_target (c_parser *, enum pragma_context); +static void c_parser_omp_end_declare_target (c_parser *); static void c_parser_omp_declare (c_parser *, enum pragma_context); /* These Objective-C parser functions are only ever called when @@ -8803,6 +8806,13 @@ c_parser_pragma (c_parser *parser, enum c_parser_omp_threadprivate (parser); return false; + case PRAGMA_OMP_TARGET: + return c_parser_omp_target (parser, context); + + case PRAGMA_OMP_END_DECLARE_TARGET: + c_parser_omp_end_declare_target (parser); + return false; + case PRAGMA_OMP_SECTION: error_at (c_parser_peek_token (parser)->location, "%<#pragma omp section%> may only be used in " @@ -8996,6 +9006,8 @@ c_parser_omp_clause_name (c_parser *pars case 't': if (!strcmp ("taskgroup", p)) result = PRAGMA_OMP_CLAUSE_TASKGROUP; + else if (!strcmp ("thread_limit", p)) + result = PRAGMA_OMP_CLAUSE_THREAD_LIMIT; else if (!strcmp ("to", p)) result = PRAGMA_OMP_CLAUSE_TO; break; @@ -9064,22 +9076,70 @@ c_parser_omp_variable_list (c_parser *pa t = lookup_name (c_parser_peek_token (parser)->value); if (t == NULL_TREE) - undeclared_variable (c_parser_peek_token (parser)->location, - c_parser_peek_token (parser)->value); - else if (t == error_mark_node) + { + undeclared_variable (c_parser_peek_token (parser)->location, + c_parser_peek_token (parser)->value); + t = error_mark_node; + } + + c_parser_consume_token (parser); + + if (t == error_mark_node) ; else if (kind != 0) { - tree u = build_omp_clause (clause_loc, kind); - OMP_CLAUSE_DECL (u) = t; - OMP_CLAUSE_CHAIN (u) = list; - list = u; + switch (kind) + { + case OMP_CLAUSE_MAP: + case OMP_CLAUSE_FROM: + case OMP_CLAUSE_TO: + case OMP_CLAUSE_DEPEND: + while (c_parser_next_token_is (parser, CPP_OPEN_SQUARE)) + { + tree low_bound = NULL_TREE, length = NULL_TREE; + + c_parser_consume_token (parser); + if (!c_parser_next_token_is (parser, CPP_COLON)) + low_bound = c_parser_expression (parser).value; + if (c_parser_next_token_is (parser, CPP_CLOSE_SQUARE)) + length = integer_one_node; + else + { + /* Look for `:'. */ + if (!c_parser_require (parser, CPP_COLON, + "expected %<:%>")) + { + t = error_mark_node; + break; + } + if (!c_parser_next_token_is (parser, CPP_CLOSE_SQUARE)) + length = c_parser_expression (parser).value; + } + /* Look for the closing `]'. */ + if (!c_parser_require (parser, CPP_CLOSE_SQUARE, + "expected %<]%>")) + { + t = error_mark_node; + break; + } + t = tree_cons (low_bound, length, t); + } + break; + default: + break; + } + + if (t != error_mark_node) + { + tree u = build_omp_clause (clause_loc, kind); + OMP_CLAUSE_DECL (u) = t; + OMP_CLAUSE_CHAIN (u) = list; + list = u; + } } else list = tree_cons (t, NULL_TREE, list); - c_parser_consume_token (parser); - if (c_parser_next_token_is_not (parser, CPP_COMMA)) break; @@ -9401,7 +9461,7 @@ c_parser_omp_clause_private (c_parser *p One of: + * - & ^ | && || max min */ static tree -c_parser_omp_clause_reduction (c_parser *parser, tree list, bool declare_simd) +c_parser_omp_clause_reduction (c_parser *parser, tree list) { location_t clause_loc = c_parser_peek_token (parser)->location; if (c_parser_require (parser, CPP_OPEN_PAREN, "expected %<(%>")) @@ -9463,8 +9523,7 @@ c_parser_omp_clause_reduction (c_parser tree nl, c; nl = c_parser_omp_variable_list (parser, clause_loc, - OMP_CLAUSE_REDUCTION, list, - declare_simd); + OMP_CLAUSE_REDUCTION, list, false); for (c = nl; c != list; c = OMP_CLAUSE_CHAIN (c)) OMP_CLAUSE_REDUCTION_CODE (c) = code; @@ -9622,24 +9681,7 @@ static tree c_parser_omp_clause_cancelkind (c_parser *parser ATTRIBUTE_UNUSED, enum omp_clause_code code, tree list) { - tree c; - location_t loc = c_parser_peek_token (parser)->location; - - for (c = list; c; c = OMP_CLAUSE_CHAIN (c)) - switch (OMP_CLAUSE_CODE (c)) - { - case OMP_CLAUSE_PARALLEL: - case OMP_CLAUSE_FOR: - case OMP_CLAUSE_SECTIONS: - case OMP_CLAUSE_TASKGROUP: - error_at (loc, "only one of %, %, % " - "and % clauses can be specified"); - break; - default: - break; - } - - c = build_omp_clause (loc, code); + tree c = build_omp_clause (c_parser_peek_token (parser)->location, code); OMP_CLAUSE_CHAIN (c) = list; return c; @@ -9690,6 +9732,51 @@ c_parser_omp_clause_num_teams (c_parser } /* OpenMP 4.0: + thread_limit ( expression ) */ + +static tree +c_parser_omp_clause_thread_limit (c_parser *parser, tree list) +{ + location_t num_teams_loc = c_parser_peek_token (parser)->location; + if (c_parser_require (parser, CPP_OPEN_PAREN, "expected %<(%>")) + { + location_t expr_loc = c_parser_peek_token (parser)->location; + tree c, t = c_parser_expression (parser).value; + mark_exp_read (t); + t = c_fully_fold (t, false, NULL); + + c_parser_skip_until_found (parser, CPP_CLOSE_PAREN, "expected %<)%>"); + + if (!INTEGRAL_TYPE_P (TREE_TYPE (t))) + { + c_parser_error (parser, "expected integer expression"); + return list; + } + + /* Attempt to statically determine when the number isn't positive. */ + c = fold_build2_loc (expr_loc, LE_EXPR, boolean_type_node, t, + build_int_cst (TREE_TYPE (t), 0)); + if (CAN_HAVE_LOCATION_P (c)) + SET_EXPR_LOCATION (c, expr_loc); + if (c == boolean_true_node) + { + warning_at (expr_loc, 0, "% value must be positive"); + t = integer_one_node; + } + + check_no_duplicate_clause (list, OMP_CLAUSE_THREAD_LIMIT, + "thread_limit"); + + c = build_omp_clause (num_teams_loc, OMP_CLAUSE_THREAD_LIMIT); + OMP_CLAUSE_THREAD_LIMIT_EXPR (c) = t; + OMP_CLAUSE_CHAIN (c) = list; + list = c; + } + + return list; +} + +/* OpenMP 4.0: aligned ( variable-list ) aligned ( variable-list : constant-expression ) */ @@ -10106,7 +10193,8 @@ c_parser_omp_clause_uniform (c_parser *p static tree c_parser_omp_all_clauses (c_parser *parser, omp_clause_mask mask, - const char *where, bool declare_simd) + const char *where, bool finish_p = true, + bool declare_simd = false) { tree clauses = NULL; bool first = true; @@ -10121,7 +10209,6 @@ c_parser_omp_all_clauses (c_parser *pars if (!first && c_parser_next_token_is (parser, CPP_COMMA)) c_parser_consume_token (parser); - first = false; here = c_parser_peek_token (parser)->location; c_kind = c_parser_omp_clause_name (parser); @@ -10180,8 +10267,7 @@ c_parser_omp_all_clauses (c_parser *pars c_name = "private"; break; case PRAGMA_OMP_CLAUSE_REDUCTION: - clauses = c_parser_omp_clause_reduction (parser, clauses, - declare_simd); + clauses = c_parser_omp_clause_reduction (parser, clauses); c_name = "reduction"; break; case PRAGMA_OMP_CLAUSE_SCHEDULE: @@ -10211,24 +10297,37 @@ c_parser_omp_all_clauses (c_parser *pars = c_parser_omp_clause_cancelkind (parser, OMP_CLAUSE_PARALLEL, clauses); c_name = "parallel"; + if (!first) + { + clause_not_first: + error_at (here, "%qs must be the first clause of %qs", + c_name, where); + clauses = prev; + } break; case PRAGMA_OMP_CLAUSE_FOR: clauses = c_parser_omp_clause_cancelkind (parser, OMP_CLAUSE_FOR, clauses); c_name = "for"; + if (!first) + goto clause_not_first; break; case PRAGMA_OMP_CLAUSE_SECTIONS: clauses = c_parser_omp_clause_cancelkind (parser, OMP_CLAUSE_SECTIONS, clauses); c_name = "sections"; + if (!first) + goto clause_not_first; break; case PRAGMA_OMP_CLAUSE_TASKGROUP: clauses = c_parser_omp_clause_cancelkind (parser, OMP_CLAUSE_TASKGROUP, clauses); c_name = "taskgroup"; + if (!first) + goto clause_not_first; break; case PRAGMA_OMP_CLAUSE_TO: clauses = c_parser_omp_clause_to (parser, clauses); @@ -10246,6 +10345,10 @@ c_parser_omp_all_clauses (c_parser *pars clauses = c_parser_omp_clause_num_teams (parser, clauses); c_name = "num_teams"; break; + case PRAGMA_OMP_CLAUSE_THREAD_LIMIT: + clauses = c_parser_omp_clause_thread_limit (parser, clauses); + c_name = "thread_limit"; + break; case PRAGMA_OMP_CLAUSE_ALIGNED: clauses = c_parser_omp_clause_aligned (parser, clauses, declare_simd); @@ -10288,6 +10391,8 @@ c_parser_omp_all_clauses (c_parser *pars goto saw_error; } + first = false; + if (((mask >> c_kind) & 1) == 0 && !parser->error) { /* Remove the invalid clause(s) from the list to avoid @@ -10300,10 +10405,10 @@ c_parser_omp_all_clauses (c_parser *pars saw_error: c_parser_skip_to_pragma_eol (parser); - if (declare_simd) - return clauses; + if (finish_p) + return c_finish_omp_clauses (clauses); - return c_finish_omp_clauses (clauses); + return clauses; } /* OpenMP 2.5: @@ -10785,7 +10890,7 @@ c_parser_omp_flush (c_parser *parser) static tree c_parser_omp_for_loop (location_t loc, c_parser *parser, enum tree_code code, - tree clauses, tree *par_clauses) + tree clauses, tree *cclauses) { tree decl, cond, incr, save_break, save_cont, body, init, stmt, cl; tree declv, condv, incrv, initv, ret = NULL; @@ -11017,10 +11122,11 @@ c_parser_omp_for_loop (location_t loc, c incrv, body, NULL); if (stmt) { - if (par_clauses != NULL) + if (cclauses != NULL + && cclauses[C_OMP_CLAUSE_SPLIT_PARALLEL] != NULL) { tree *c; - for (c = par_clauses; *c ; ) + for (c = &cclauses[C_OMP_CLAUSE_SPLIT_PARALLEL]; *c ; ) if (OMP_CLAUSE_CODE (*c) != OMP_CLAUSE_FIRSTPRIVATE && OMP_CLAUSE_CODE (*c) != OMP_CLAUSE_LASTPRIVATE) c = &OMP_CLAUSE_CHAIN (*c); @@ -11069,6 +11175,20 @@ pop_scopes: return ret; } +/* Helper function for OpenMP parsing, split clauses and call + finish_omp_clauses on each of the set of clauses afterwards. */ + +static void +omp_split_clauses (location_t loc, enum tree_code code, + omp_clause_mask mask, tree clauses, tree *cclauses) +{ + int i; + c_omp_split_clauses (loc, code, mask, clauses, cclauses); + for (i = 0; i < C_OMP_CLAUSE_SPLIT_COUNT; i++) + if (cclauses[i]) + cclauses[i] = c_finish_omp_clauses (cclauses[i]); +} + /* OpenMP 4.0: #pragma omp simd simd-clause[optseq] new-line for-loop @@ -11086,15 +11206,24 @@ pop_scopes: | (OMP_CLAUSE_MASK_1 << PRAGMA_OMP_CLAUSE_COLLAPSE)) static tree -c_parser_omp_simd (location_t loc, c_parser *parser) +c_parser_omp_simd (location_t loc, c_parser *parser, + char *p_name, omp_clause_mask mask, tree *cclauses) { tree block, clauses, ret; - clauses = c_parser_omp_all_clauses (parser, OMP_SIMD_CLAUSE_MASK, - "#pragma omp simd", false); + strcat (p_name, " simd"); + mask |= OMP_SIMD_CLAUSE_MASK; + mask &= ~(OMP_CLAUSE_MASK_1 << PRAGMA_OMP_CLAUSE_ORDERED); + + clauses = c_parser_omp_all_clauses (parser, mask, p_name, cclauses == NULL); + if (cclauses) + { + omp_split_clauses (loc, OMP_SIMD, mask, clauses, cclauses); + clauses = cclauses[C_OMP_CLAUSE_SPLIT_SIMD]; + } block = c_begin_compound_stmt (true); - ret = c_parser_omp_for_loop (loc, parser, OMP_SIMD, clauses, NULL); + ret = c_parser_omp_for_loop (loc, parser, OMP_SIMD, clauses, cclauses); block = c_end_compound_stmt (loc, block, true); add_stmt (block); @@ -11123,12 +11252,15 @@ c_parser_omp_simd (location_t loc, c_par | (OMP_CLAUSE_MASK_1 << PRAGMA_OMP_CLAUSE_NOWAIT)) static tree -c_parser_omp_for (location_t loc, c_parser *parser) +c_parser_omp_for (location_t loc, c_parser *parser, + char *p_name, omp_clause_mask mask, tree *cclauses) { tree block, clauses, ret; - enum tree_code code = OMP_FOR; - omp_clause_mask mask = OMP_FOR_CLAUSE_MASK; - const char *p_name = "#pragma omp for"; + + strcat (p_name, " for"); + mask |= OMP_FOR_CLAUSE_MASK; + if (cclauses) + mask &= ~(OMP_CLAUSE_MASK_1 << PRAGMA_OMP_CLAUSE_NOWAIT); if (c_parser_next_token_is (parser, CPP_NAME)) { @@ -11136,17 +11268,35 @@ c_parser_omp_for (location_t loc, c_pars if (strcmp (p, "simd") == 0) { - c_parser_consume_token (parser); - /* code = OMP_FOR_SIMD; */ - mask |= OMP_SIMD_CLAUSE_MASK; - p_name = "#pragma omp for simd"; + tree cclauses_buf[C_OMP_CLAUSE_SPLIT_COUNT]; + if (cclauses == NULL) + cclauses = cclauses_buf; + + c_parser_consume_token (parser); + block = c_begin_compound_stmt (true); + ret = c_parser_omp_simd (loc, parser, p_name, mask, cclauses); + block = c_end_compound_stmt (loc, block, true); + if (ret == NULL_TREE) + return ret; + ret = make_node (OMP_FOR); + TREE_TYPE (ret) = void_type_node; + OMP_FOR_BODY (ret) = block; + OMP_FOR_CLAUSES (ret) = cclauses[C_OMP_CLAUSE_SPLIT_FOR]; + SET_EXPR_LOCATION (ret, loc); + add_stmt (ret); + return ret; } } - clauses = c_parser_omp_all_clauses (parser, mask, p_name, false); + clauses = c_parser_omp_all_clauses (parser, mask, p_name, cclauses == NULL); + if (cclauses) + { + omp_split_clauses (loc, OMP_FOR, mask, clauses, cclauses); + clauses = cclauses[C_OMP_CLAUSE_SPLIT_FOR]; + } block = c_begin_compound_stmt (true); - ret = c_parser_omp_for_loop (loc, parser, code, clauses, NULL); + ret = c_parser_omp_for_loop (loc, parser, OMP_FOR, clauses, cclauses); block = c_end_compound_stmt (loc, block, true); add_stmt (block); @@ -11270,12 +11420,22 @@ c_parser_omp_sections_scope (location_t | (OMP_CLAUSE_MASK_1 << PRAGMA_OMP_CLAUSE_NOWAIT)) static tree -c_parser_omp_sections (location_t loc, c_parser *parser) +c_parser_omp_sections (location_t loc, c_parser *parser, + char *p_name, omp_clause_mask mask, tree *cclauses) { tree block, clauses, ret; - clauses = c_parser_omp_all_clauses (parser, OMP_SECTIONS_CLAUSE_MASK, - "#pragma omp sections", false); + strcat (p_name, " sections"); + mask |= OMP_SECTIONS_CLAUSE_MASK; + if (cclauses) + mask &= ~(OMP_CLAUSE_MASK_1 << PRAGMA_OMP_CLAUSE_NOWAIT); + + clauses = c_parser_omp_all_clauses (parser, mask, p_name, cclauses == NULL); + if (cclauses) + { + omp_split_clauses (loc, OMP_SECTIONS, mask, clauses, cclauses); + clauses = cclauses[C_OMP_CLAUSE_SPLIT_SECTIONS]; + } block = c_begin_compound_stmt (true); ret = c_parser_omp_sections_scope (loc, parser); @@ -11307,93 +11467,60 @@ c_parser_omp_sections (location_t loc, c | (OMP_CLAUSE_MASK_1 << PRAGMA_OMP_CLAUSE_PROC_BIND)) static tree -c_parser_omp_parallel (location_t loc, c_parser *parser) +c_parser_omp_parallel (location_t loc, c_parser *parser, + char *p_name, omp_clause_mask mask, tree *cclauses) { - enum pragma_kind p_kind = PRAGMA_OMP_PARALLEL; - const char *p_name = "#pragma omp parallel"; - tree stmt, clauses, par_clause, ws_clause, block; - omp_clause_mask mask = OMP_PARALLEL_CLAUSE_MASK; - tree cclauses[C_OMP_CLAUSE_SPLIT_COUNT]; + tree stmt, clauses, block; + + strcat (p_name, " parallel"); + mask |= OMP_PARALLEL_CLAUSE_MASK; if (c_parser_next_token_is_keyword (parser, RID_FOR)) { + tree cclauses_buf[C_OMP_CLAUSE_SPLIT_COUNT]; + if (cclauses == NULL) + cclauses = cclauses_buf; + c_parser_consume_token (parser); - p_kind = PRAGMA_OMP_PARALLEL_FOR; - p_name = "#pragma omp parallel for"; - mask |= OMP_FOR_CLAUSE_MASK; - mask &= ~(OMP_CLAUSE_MASK_1 << PRAGMA_OMP_CLAUSE_NOWAIT); - if (c_parser_next_token_is (parser, CPP_NAME)) - { - const char *p - = IDENTIFIER_POINTER (c_parser_peek_token (parser)->value); - if (strcmp (p, "simd") == 0) - { - c_parser_consume_token (parser); - p_kind = PRAGMA_OMP_PARALLEL_FOR_SIMD; - p_name = "#pragma omp parallel for simd"; - mask |= OMP_SIMD_CLAUSE_MASK; - } - } + block = c_begin_omp_parallel (); + c_parser_omp_for (loc, parser, p_name, mask, cclauses); + stmt + = c_finish_omp_parallel (loc, cclauses[C_OMP_CLAUSE_SPLIT_PARALLEL], + block); + OMP_PARALLEL_COMBINED (stmt) = 1; + return stmt; + } + else if (cclauses) + { + error_at (loc, "expected % after %qs", p_name); + c_parser_skip_to_pragma_eol (parser); + return NULL_TREE; } else if (c_parser_next_token_is (parser, CPP_NAME)) { const char *p = IDENTIFIER_POINTER (c_parser_peek_token (parser)->value); if (strcmp (p, "sections") == 0) { + tree cclauses_buf[C_OMP_CLAUSE_SPLIT_COUNT]; + if (cclauses == NULL) + cclauses = cclauses_buf; + c_parser_consume_token (parser); - p_kind = PRAGMA_OMP_PARALLEL_SECTIONS; - p_name = "#pragma omp parallel sections"; - mask |= OMP_SECTIONS_CLAUSE_MASK; - mask &= ~(OMP_CLAUSE_MASK_1 << PRAGMA_OMP_CLAUSE_NOWAIT); + block = c_begin_omp_parallel (); + c_parser_omp_sections (loc, parser, p_name, mask, cclauses); + stmt = c_finish_omp_parallel (loc, + cclauses[C_OMP_CLAUSE_SPLIT_PARALLEL], + block); + OMP_PARALLEL_COMBINED (stmt) = 1; + return stmt; } } - clauses = c_parser_omp_all_clauses (parser, mask, p_name, false); - - switch (p_kind) - { - case PRAGMA_OMP_PARALLEL: - block = c_begin_omp_parallel (); - c_parser_statement (parser); - stmt = c_finish_omp_parallel (loc, clauses, block); - break; - - case PRAGMA_OMP_PARALLEL_FOR: - block = c_begin_omp_parallel (); - c_omp_split_clauses (loc, OMP_FOR, mask, clauses, cclauses); - par_clause = cclauses[C_OMP_CLAUSE_SPLIT_PARALLEL]; - ws_clause = cclauses[C_OMP_CLAUSE_SPLIT_FOR]; - c_parser_omp_for_loop (loc, parser, OMP_FOR, ws_clause, &par_clause); - stmt = c_finish_omp_parallel (loc, par_clause, block); - OMP_PARALLEL_COMBINED (stmt) = 1; - break; + clauses = c_parser_omp_all_clauses (parser, mask, p_name, cclauses == NULL); - case PRAGMA_OMP_PARALLEL_FOR_SIMD: - block = c_begin_omp_parallel (); - c_omp_split_clauses (loc, OMP_FOR, mask, clauses, cclauses); - par_clause = cclauses[C_OMP_CLAUSE_SPLIT_PARALLEL]; - ws_clause = cclauses[C_OMP_CLAUSE_SPLIT_FOR]; - c_parser_omp_for_loop (loc, parser, OMP_FOR /*_SIMD*/, ws_clause, - &par_clause); - stmt = c_finish_omp_parallel (loc, par_clause, block); - OMP_PARALLEL_COMBINED (stmt) = 1; - break; - - case PRAGMA_OMP_PARALLEL_SECTIONS: - block = c_begin_omp_parallel (); - c_omp_split_clauses (loc, OMP_SECTIONS, mask, clauses, cclauses); - par_clause = cclauses[C_OMP_CLAUSE_SPLIT_PARALLEL]; - ws_clause = cclauses[C_OMP_CLAUSE_SPLIT_SECTIONS]; - stmt = c_parser_omp_sections_scope (loc, parser); - if (stmt) - OMP_SECTIONS_CLAUSES (stmt) = ws_clause; - stmt = c_finish_omp_parallel (loc, par_clause, block); - OMP_PARALLEL_COMBINED (stmt) = 1; - break; - - default: - gcc_unreachable (); - } + block = c_begin_omp_parallel (); + c_parser_statement (parser); + stmt = c_finish_omp_parallel (loc, clauses, block); return stmt; } @@ -11420,7 +11547,7 @@ c_parser_omp_single (location_t loc, c_p OMP_SINGLE_CLAUSES (stmt) = c_parser_omp_all_clauses (parser, OMP_SINGLE_CLAUSE_MASK, - "#pragma omp single", false); + "#pragma omp single"); OMP_SINGLE_BODY (stmt) = c_parser_omp_structured_block (parser); return add_stmt (stmt); @@ -11449,7 +11576,7 @@ c_parser_omp_task (location_t loc, c_par tree clauses, block; clauses = c_parser_omp_all_clauses (parser, OMP_TASK_CLAUSE_MASK, - "#pragma omp task", false); + "#pragma omp task"); block = c_begin_omp_task (); c_parser_statement (parser); @@ -11519,7 +11646,7 @@ c_parser_omp_cancel (c_parser *parser) c_parser_consume_pragma (parser); tree clauses = c_parser_omp_all_clauses (parser, OMP_CANCEL_CLAUSE_MASK, - "#pragma omp cancel", false); + "#pragma omp cancel"); c_finish_omp_cancel (loc, clauses); } @@ -11562,12 +11689,280 @@ c_parser_omp_cancellation_point (c_parse clauses = c_parser_omp_all_clauses (parser, OMP_CANCELLATION_POINT_CLAUSE_MASK, - "#pragma omp cancellation point", false); + "#pragma omp cancellation point"); c_finish_omp_cancellation_point (loc, clauses); } /* OpenMP 4.0: + #pragma omp distribute distribute-clause[optseq] new-line + for-loop */ + +#define OMP_DISTRIBUTE_CLAUSE_MASK \ + ( (OMP_CLAUSE_MASK_1 << PRAGMA_OMP_CLAUSE_PRIVATE) \ + | (OMP_CLAUSE_MASK_1 << PRAGMA_OMP_CLAUSE_FIRSTPRIVATE) \ + | (OMP_CLAUSE_MASK_1 << PRAGMA_OMP_CLAUSE_DIST_SCHEDULE)\ + | (OMP_CLAUSE_MASK_1 << PRAGMA_OMP_CLAUSE_COLLAPSE)) + +static tree +c_parser_omp_distribute (location_t loc, c_parser *parser, + char *p_name, omp_clause_mask mask, tree *cclauses) +{ + tree clauses, block, ret; + + strcat (p_name, " distribute"); + mask |= OMP_DISTRIBUTE_CLAUSE_MASK; + + if (c_parser_next_token_is (parser, CPP_NAME)) + { + const char *p = IDENTIFIER_POINTER (c_parser_peek_token (parser)->value); + bool simd = false; + bool parallel = false; + + if (strcmp (p, "simd") == 0) + simd = true; + else + parallel = strcmp (p, "parallel") == 0; + if (parallel || simd) + { + tree cclauses_buf[C_OMP_CLAUSE_SPLIT_COUNT]; + if (cclauses == NULL) + cclauses = cclauses_buf; + c_parser_consume_token (parser); + block = c_begin_compound_stmt (true); + if (simd) + ret = c_parser_omp_simd (loc, parser, p_name, mask, cclauses); + else + ret = c_parser_omp_parallel (loc, parser, p_name, mask, cclauses); + block = c_end_compound_stmt (loc, block, true); + if (ret == NULL) + return ret; + ret = make_node (OMP_DISTRIBUTE); + TREE_TYPE (ret) = void_type_node; + OMP_FOR_BODY (ret) = block; + OMP_FOR_CLAUSES (ret) = cclauses[C_OMP_CLAUSE_SPLIT_DISTRIBUTE]; + SET_EXPR_LOCATION (ret, loc); + add_stmt (ret); + return ret; + } + } + + clauses = c_parser_omp_all_clauses (parser, mask, p_name, cclauses == NULL); + if (cclauses) + { + omp_split_clauses (loc, OMP_DISTRIBUTE, mask, clauses, cclauses); + clauses = cclauses[C_OMP_CLAUSE_SPLIT_DISTRIBUTE]; + } + + block = c_begin_compound_stmt (true); + ret = c_parser_omp_for_loop (loc, parser, OMP_DISTRIBUTE, clauses, NULL); + block = c_end_compound_stmt (loc, block, true); + add_stmt (block); + + return ret; +} + +/* OpenMP 4.0: + # pragma omp teams teams-clause[optseq] new-line + structured-block */ + +#define OMP_TEAMS_CLAUSE_MASK \ + ( (OMP_CLAUSE_MASK_1 << PRAGMA_OMP_CLAUSE_PRIVATE) \ + | (OMP_CLAUSE_MASK_1 << PRAGMA_OMP_CLAUSE_FIRSTPRIVATE) \ + | (OMP_CLAUSE_MASK_1 << PRAGMA_OMP_CLAUSE_SHARED) \ + | (OMP_CLAUSE_MASK_1 << PRAGMA_OMP_CLAUSE_REDUCTION) \ + | (OMP_CLAUSE_MASK_1 << PRAGMA_OMP_CLAUSE_NUM_TEAMS) \ + | (OMP_CLAUSE_MASK_1 << PRAGMA_OMP_CLAUSE_THREAD_LIMIT) \ + | (OMP_CLAUSE_MASK_1 << PRAGMA_OMP_CLAUSE_DEFAULT)) + +static tree +c_parser_omp_teams (location_t loc, c_parser *parser, + char *p_name, omp_clause_mask mask, tree *cclauses) +{ + tree clauses, block, ret; + + strcat (p_name, " teams"); + mask |= OMP_TEAMS_CLAUSE_MASK; + + if (c_parser_next_token_is (parser, CPP_NAME)) + { + const char *p = IDENTIFIER_POINTER (c_parser_peek_token (parser)->value); + if (strcmp (p, "distribute") == 0) + { + tree cclauses_buf[C_OMP_CLAUSE_SPLIT_COUNT]; + if (cclauses == NULL) + cclauses = cclauses_buf; + + c_parser_consume_token (parser); + block = c_begin_compound_stmt (true); + ret = c_parser_omp_distribute (loc, parser, p_name, mask, cclauses); + block = c_end_compound_stmt (loc, block, true); + if (ret == NULL) + return ret; + clauses = cclauses[C_OMP_CLAUSE_SPLIT_TEAMS]; + ret = make_node (OMP_TEAMS); + TREE_TYPE (ret) = void_type_node; + OMP_TEAMS_CLAUSES (ret) = clauses; + OMP_TEAMS_BODY (ret) = block; + return add_stmt (ret); + } + } + + clauses = c_parser_omp_all_clauses (parser, mask, p_name, cclauses == NULL); + if (cclauses) + { + omp_split_clauses (loc, OMP_TEAMS, mask, clauses, cclauses); + clauses = cclauses[C_OMP_CLAUSE_SPLIT_TEAMS]; + } + + tree stmt = make_node (OMP_TEAMS); + TREE_TYPE (stmt) = void_type_node; + OMP_TEAMS_CLAUSES (stmt) = clauses; + OMP_TEAMS_BODY (stmt) = c_parser_omp_structured_block (parser); + + return add_stmt (stmt); +} + +/* OpenMP 4.0: + # pragma omp target data target-data-clause[optseq] new-line + structured-block */ + +#define OMP_TARGET_DATA_CLAUSE_MASK \ + ( (OMP_CLAUSE_MASK_1 << PRAGMA_OMP_CLAUSE_DEVICE) \ + | (OMP_CLAUSE_MASK_1 << PRAGMA_OMP_CLAUSE_MAP) \ + | (OMP_CLAUSE_MASK_1 << PRAGMA_OMP_CLAUSE_IF)) + +static tree +c_parser_omp_target_data (location_t loc, c_parser *parser) +{ + tree stmt = make_node (OMP_TARGET_DATA); + TREE_TYPE (stmt) = void_type_node; + + OMP_TARGET_DATA_CLAUSES (stmt) + = c_parser_omp_all_clauses (parser, OMP_TARGET_DATA_CLAUSE_MASK, + "#pragma omp target data"); + OMP_TARGET_DATA_BODY (stmt) = c_parser_omp_structured_block (parser); + + SET_EXPR_LOCATION (stmt, loc); + return add_stmt (stmt); +} + +/* OpenMP 4.0: + # pragma omp target update target-update-clause[optseq] new-line */ + +#define OMP_TARGET_UPDATE_CLAUSE_MASK \ + ( (OMP_CLAUSE_MASK_1 << PRAGMA_OMP_CLAUSE_FROM) \ + | (OMP_CLAUSE_MASK_1 << PRAGMA_OMP_CLAUSE_TO) \ + | (OMP_CLAUSE_MASK_1 << PRAGMA_OMP_CLAUSE_DEVICE) \ + | (OMP_CLAUSE_MASK_1 << PRAGMA_OMP_CLAUSE_IF)) + +static bool +c_parser_omp_target_update (location_t loc, c_parser *parser, + enum pragma_context context) +{ + if (context == pragma_stmt) + { + error_at (loc, + "%<#pragma omp target update%> may only be " + "used in compound statements"); + c_parser_skip_to_pragma_eol (parser); + return false; + } + + tree clauses + = c_parser_omp_all_clauses (parser, OMP_TARGET_UPDATE_CLAUSE_MASK, + "#pragma omp target update"); + if (find_omp_clause (clauses, OMP_CLAUSE_TO) == NULL_TREE + && find_omp_clause (clauses, OMP_CLAUSE_FROM) == NULL_TREE) + { + error_at (loc, + "%<#pragma omp target update must contain at least one " + "% or % clauses"); + return false; + } + + tree stmt = make_node (OMP_TARGET_UPDATE); + TREE_TYPE (stmt) = void_type_node; + OMP_TARGET_UPDATE_CLAUSES (stmt) = clauses; + SET_EXPR_LOCATION (stmt, loc); + add_stmt (stmt); + return false; +} + +/* OpenMP 4.0: + # pragma omp target target-clause[optseq] new-line + structured-block */ + +#define OMP_TARGET_CLAUSE_MASK \ + ( (OMP_CLAUSE_MASK_1 << PRAGMA_OMP_CLAUSE_DEVICE) \ + | (OMP_CLAUSE_MASK_1 << PRAGMA_OMP_CLAUSE_MAP) \ + | (OMP_CLAUSE_MASK_1 << PRAGMA_OMP_CLAUSE_IF)) + +static bool +c_parser_omp_target (c_parser *parser, enum pragma_context context) +{ + location_t loc = c_parser_peek_token (parser)->location; + c_parser_consume_pragma (parser); + + if (context != pragma_stmt && context != pragma_compound) + { + c_parser_error (parser, "expected declaration specifiers"); + c_parser_skip_to_pragma_eol (parser); + return false; + } + + if (c_parser_next_token_is (parser, CPP_NAME)) + { + const char *p = IDENTIFIER_POINTER (c_parser_peek_token (parser)->value); + + if (strcmp (p, "data") == 0) + { + c_parser_consume_token (parser); + c_parser_omp_target_data (loc, parser); + return true; + } + else if (strcmp (p, "update") == 0) + { + c_parser_consume_token (parser); + return c_parser_omp_target_update (loc, parser, context); + } + else if (strcmp (p, "teams") == 0) + { + tree cclauses[C_OMP_CLAUSE_SPLIT_COUNT]; + char p_name[sizeof ("#pragma omp target teams distribute " + "parallel for simd")]; + + c_parser_consume_token (parser); + strcpy (p_name, "#pragma omp target"); + tree block = c_begin_compound_stmt (true); + tree ret = c_parser_omp_teams (loc, parser, p_name, + OMP_TARGET_CLAUSE_MASK, cclauses); + block = c_end_compound_stmt (loc, block, true); + if (ret == NULL) + return ret; + tree stmt = make_node (OMP_TARGET); + TREE_TYPE (stmt) = void_type_node; + OMP_TARGET_CLAUSES (stmt) = cclauses[C_OMP_CLAUSE_SPLIT_TARGET]; + OMP_TARGET_BODY (stmt) = block; + add_stmt (stmt); + return true; + } + } + + tree stmt = make_node (OMP_TARGET); + TREE_TYPE (stmt) = void_type_node; + + OMP_TARGET_CLAUSES (stmt) + = c_parser_omp_all_clauses (parser, OMP_TARGET_CLAUSE_MASK, + "#pragma omp target"); + OMP_TARGET_BODY (stmt) = c_parser_omp_structured_block (parser); + + SET_EXPR_LOCATION (stmt, loc); + add_stmt (stmt); + return true; +} + +/* OpenMP 4.0: # pragma omp declare simd declare-simd-clauses[optseq] new-line */ #define OMP_DECLARE_SIMD_CLAUSE_MASK \ @@ -11575,7 +11970,6 @@ c_parser_omp_cancellation_point (c_parse | (OMP_CLAUSE_MASK_1 << PRAGMA_OMP_CLAUSE_LINEAR) \ | (OMP_CLAUSE_MASK_1 << PRAGMA_OMP_CLAUSE_ALIGNED) \ | (OMP_CLAUSE_MASK_1 << PRAGMA_OMP_CLAUSE_UNIFORM) \ - | (OMP_CLAUSE_MASK_1 << PRAGMA_OMP_CLAUSE_REDUCTION) \ | (OMP_CLAUSE_MASK_1 << PRAGMA_OMP_CLAUSE_INBRANCH) \ | (OMP_CLAUSE_MASK_1 << PRAGMA_OMP_CLAUSE_NOTINBRANCH)) @@ -11584,7 +11978,7 @@ c_parser_omp_declare_simd (c_parser *par { vec clauses = vNULL; tree cl = c_parser_omp_all_clauses (parser, OMP_DECLARE_SIMD_CLAUSE_MASK, - "#pragma omp declare simd", true); + "#pragma omp declare simd", false, true); clauses.safe_push (cl); while (c_parser_next_token_is (parser, CPP_PRAGMA)) @@ -11606,7 +12000,7 @@ c_parser_omp_declare_simd (c_parser *par c_parser_consume_pragma (parser); c_parser_consume_token (parser); cl = c_parser_omp_all_clauses (parser, OMP_DECLARE_SIMD_CLAUSE_MASK, - "#pragma omp declare simd", true); + "#pragma omp declare simd", false, true); clauses.safe_push (cl); } @@ -11668,10 +12062,58 @@ c_parser_omp_declare_simd (c_parser *par clauses.release (); } +/* OpenMP 4.0: + # pragma omp declare target new-line + declarations and definitions + # pragma omp end declare target new-line */ + +static void +c_parser_omp_declare_target (c_parser *parser) +{ + c_parser_skip_to_pragma_eol (parser); + current_omp_declare_target_attribute++; +} + +static void +c_parser_omp_end_declare_target (c_parser *parser) +{ + location_t loc = c_parser_peek_token (parser)->location; + c_parser_consume_pragma (parser); + if (c_parser_next_token_is (parser, CPP_NAME) + && strcmp (IDENTIFIER_POINTER (c_parser_peek_token (parser)->value), + "declare") == 0) + { + c_parser_consume_token (parser); + if (c_parser_next_token_is (parser, CPP_NAME) + && strcmp (IDENTIFIER_POINTER (c_parser_peek_token (parser)->value), + "target") == 0) + c_parser_consume_token (parser); + else + { + c_parser_error (parser, "expected %"); + c_parser_skip_to_pragma_eol (parser); + return; + } + } + else + { + c_parser_error (parser, "expected %"); + c_parser_skip_to_pragma_eol (parser); + return; + } + c_parser_skip_to_pragma_eol (parser); + if (!current_omp_declare_target_attribute) + error_at (loc, "%<#pragma omp end declare target%> without corresponding " + "%<#pragma omp declare target%>"); + else + current_omp_declare_target_attribute--; +} + /* OpenMP 4.0 #pragma omp declare simd declare-simd-clauses[optseq] new-line #pragma omp declare reduction (reduction-id : typename-list : expression) \ - identity-clause[opt] new-line */ + identity-clause[opt] new-line + #pragma omp declare target new-line */ static void c_parser_omp_declare (c_parser *parser, enum pragma_context context) @@ -11692,9 +12134,16 @@ c_parser_omp_declare (c_parser *parser, c_parser_omp_declare_reduction (parser); return; } */ + if (strcmp (p, "target") == 0) + { + c_parser_consume_token (parser); + c_parser_omp_declare_target (parser); + return; + } } - c_parser_error (parser, "expected % or %"); + c_parser_error (parser, "expected % or % " + "or %"); c_parser_skip_to_pragma_eol (parser); } @@ -11706,6 +12155,8 @@ c_parser_omp_construct (c_parser *parser enum pragma_kind p_kind; location_t loc; tree stmt; + char p_name[sizeof "#pragma omp teams distribute parallel for simd"]; + omp_clause_mask mask (0); loc = c_parser_peek_token (parser)->location; p_kind = c_parser_peek_token (parser)->pragma_kind; @@ -11719,8 +12170,13 @@ c_parser_omp_construct (c_parser *parser case PRAGMA_OMP_CRITICAL: stmt = c_parser_omp_critical (loc, parser); break; + case PRAGMA_OMP_DISTRIBUTE: + strcpy (p_name, "#pragma omp"); + stmt = c_parser_omp_distribute (loc, parser, p_name, mask, NULL); + break; case PRAGMA_OMP_FOR: - stmt = c_parser_omp_for (loc, parser); + strcpy (p_name, "#pragma omp"); + stmt = c_parser_omp_for (loc, parser, p_name, mask, NULL); break; case PRAGMA_OMP_MASTER: stmt = c_parser_omp_master (loc, parser); @@ -11729,13 +12185,16 @@ c_parser_omp_construct (c_parser *parser stmt = c_parser_omp_ordered (loc, parser); break; case PRAGMA_OMP_PARALLEL: - stmt = c_parser_omp_parallel (loc, parser); + strcpy (p_name, "#pragma omp"); + stmt = c_parser_omp_parallel (loc, parser, p_name, mask, NULL); break; case PRAGMA_OMP_SECTIONS: - stmt = c_parser_omp_sections (loc, parser); + strcpy (p_name, "#pragma omp"); + stmt = c_parser_omp_sections (loc, parser, p_name, mask, NULL); break; case PRAGMA_OMP_SIMD: - stmt = c_parser_omp_simd (loc, parser); + strcpy (p_name, "#pragma omp"); + stmt = c_parser_omp_simd (loc, parser, p_name, mask, NULL); break; case PRAGMA_OMP_SINGLE: stmt = c_parser_omp_single (loc, parser); @@ -11746,6 +12205,10 @@ c_parser_omp_construct (c_parser *parser case PRAGMA_OMP_TASKGROUP: c_parser_omp_taskgroup (parser); return; + case PRAGMA_OMP_TEAMS: + strcpy (p_name, "#pragma omp"); + stmt = c_parser_omp_teams (loc, parser, p_name, mask, NULL); + break; default: gcc_unreachable (); } --- gcc/c/c-decl.c.jj 2013-06-26 12:13:51.000000000 +0200 +++ gcc/c/c-decl.c 2013-07-06 18:34:37.499264094 +0200 @@ -147,6 +147,9 @@ static bool undef_nested_function; enum machine_mode c_default_pointer_mode = VOIDmode; +/* If non-zero, implicit "omp declare target" attribute is added into the + attribute lists. */ +int current_omp_declare_target_attribute; /* Each c_binding structure describes one binding of an identifier to a decl. All the decls in a scope - irrespective of namespace - are @@ -3974,6 +3977,35 @@ groktypename (struct c_type_name *type_n return type; } +/* Wrapper for decl_attributes that adds some implicit attributes + to VAR_DECLs or FUNCTION_DECLs. */ + +static tree +c_decl_attributes (tree *node, tree attributes, int flags) +{ + /* Add implicit "omp declare target" attribute if requested. */ + if (current_omp_declare_target_attribute + && ((TREE_CODE (*node) == VAR_DECL && TREE_STATIC (*node)) + || TREE_CODE (*node) == FUNCTION_DECL)) + { + if (TREE_CODE (*node) == VAR_DECL + && ((DECL_CONTEXT (*node) + && TREE_CODE (DECL_CONTEXT (*node)) == FUNCTION_DECL) + || (current_function_decl && !DECL_EXTERNAL (*node)))) + error ("%q+D in block scope inside of declare target directive", + *node); + else if (TREE_CODE (*node) == VAR_DECL + && !COMPLETE_TYPE_P (TREE_TYPE (*node))) + error ("%q+D in declare target directive does not have mappable type", + *node); + else + attributes = tree_cons (get_identifier ("omp declare target"), + NULL_TREE, attributes); + } + return decl_attributes (node, attributes, flags); +} + + /* Decode a declarator in an ordinary declaration or data definition. This is called as soon as the type information and variable name have been parsed, before parsing the initializer if any. @@ -4108,7 +4140,7 @@ start_decl (struct c_declarator *declara DECL_COMMON (decl) = 1; /* Set attributes here so if duplicate decl, will have proper attributes. */ - decl_attributes (&decl, attributes, 0); + c_decl_attributes (&decl, attributes, 0); /* Handle gnu_inline attribute. */ if (declspecs->inline_p @@ -7724,7 +7756,7 @@ start_function (struct c_declspecs *decl loc = DECL_SOURCE_LOCATION (decl1); - decl_attributes (&decl1, attributes, 0); + c_decl_attributes (&decl1, attributes, 0); if (DECL_DECLARED_INLINE_P (decl1) && DECL_UNINLINABLE (decl1) --- gcc/c/c-typeck.c.jj 2013-07-03 22:15:07.000000000 +0200 +++ gcc/c/c-typeck.c 2013-07-06 18:24:50.762931048 +0200 @@ -10730,6 +10730,435 @@ c_finish_omp_cancellation_point (locatio add_stmt (stmt); } +/* Helper function for handle_omp_array_sections. Called recursively + to handle multiple array-section-subscripts. C is the clause, + T current expression (initially OMP_CLAUSE_DECL), which is either + a TREE_LIST for array-section-subscript (TREE_PURPOSE is low-bound + expression if specified, TREE_VALUE length expression if specified, + TREE_CHAIN is what it has been specified after, or some decl. + TYPES vector is populated with array section types, MAYBE_ZERO_LEN + set to true if any of the array-section-subscript could have length + of zero (explicit or implicit), FIRST_NON_ONE is the index of the + first array-section-subscript which is known not to have length + of one. Given say: + map(a[:b][2:1][:c][:2][:d][e:f][2:5]) + FIRST_NON_ONE will be 3, array-section-subscript [:b], [2:1] and [:c] + all are or may have length of 1, array-section-subscript [:2] is the + first one knonwn not to have length 1. For array-section-subscript + <= FIRST_NON_ONE we diagnose non-contiguous arrays if low bound isn't + 0 or length isn't the array domain max + 1, for > FIRST_NON_ONE we + can if MAYBE_ZERO_LEN is false. MAYBE_ZERO_LEN will be true in the above + case though, as some lengths could be zero. */ + +static tree +handle_omp_array_sections_1 (tree c, tree t, vec &types, + bool &maybe_zero_len, unsigned int &first_non_one, + bool &pointer_based_p) +{ + tree ret, low_bound, length, type; + if (TREE_CODE (t) != TREE_LIST) + { + if (t == error_mark_node || TREE_TYPE (t) == error_mark_node) + return error_mark_node; + if (TREE_CODE (t) != VAR_DECL && TREE_CODE (t) != PARM_DECL) + { + if (DECL_P (t)) + error_at (OMP_CLAUSE_LOCATION (c), + "%qD is not a variable in %qs clause", t, + omp_clause_code_name[OMP_CLAUSE_CODE (c)]); + else + error_at (OMP_CLAUSE_LOCATION (c), + "%qE is not a variable in %qs clause", t, + omp_clause_code_name[OMP_CLAUSE_CODE (c)]); + return error_mark_node; + } + else if (OMP_CLAUSE_CODE (c) != OMP_CLAUSE_DEPEND + && TREE_CODE (t) == VAR_DECL && DECL_THREAD_LOCAL_P (t)) + { + error_at (OMP_CLAUSE_LOCATION (c), + "%qD is threadprivate variable in %qs clause", t, + omp_clause_code_name[OMP_CLAUSE_CODE (c)]); + return error_mark_node; + } + if (POINTER_TYPE_P (TREE_TYPE (t)) + && OMP_CLAUSE_CODE (c) == OMP_CLAUSE_MAP) + pointer_based_p = true; + return t; + } + + ret = handle_omp_array_sections_1 (c, TREE_CHAIN (t), types, + maybe_zero_len, first_non_one, + pointer_based_p); + if (ret == error_mark_node || ret == NULL_TREE) + return ret; + + type = TREE_TYPE (ret); + low_bound = TREE_PURPOSE (t); + length = TREE_VALUE (t); + + if (low_bound == error_mark_node || length == error_mark_node) + return error_mark_node; + + if (low_bound && !INTEGRAL_TYPE_P (TREE_TYPE (low_bound))) + { + error_at (OMP_CLAUSE_LOCATION (c), + "low bound %qE of array section does not have integral type", + low_bound); + return error_mark_node; + } + if (length && !INTEGRAL_TYPE_P (TREE_TYPE (length))) + { + error_at (OMP_CLAUSE_LOCATION (c), + "length %qE of array section does not have integral type", + length); + return error_mark_node; + } + if (low_bound + && TREE_CODE (low_bound) == INTEGER_CST + && TYPE_PRECISION (TREE_TYPE (low_bound)) + > TYPE_PRECISION (sizetype)) + low_bound = fold_convert (sizetype, low_bound); + if (length + && TREE_CODE (length) == INTEGER_CST + && TYPE_PRECISION (TREE_TYPE (length)) + > TYPE_PRECISION (sizetype)) + length = fold_convert (sizetype, length); + if (low_bound == NULL_TREE) + low_bound = integer_zero_node; + + if (length != NULL_TREE) + { + if (!integer_nonzerop (length)) + maybe_zero_len = true; + if (first_non_one == types.length () + && (TREE_CODE (length) != INTEGER_CST || integer_onep (length))) + first_non_one++; + } + if (TREE_CODE (type) == ARRAY_TYPE) + { + if (length == NULL_TREE + && (TYPE_DOMAIN (type) == NULL_TREE + || TYPE_MAX_VALUE (TYPE_DOMAIN (type)) == NULL_TREE)) + { + error_at (OMP_CLAUSE_LOCATION (c), + "for unknown bound array type length expression is " + "not optional"); + return error_mark_node; + } + if (TREE_CODE (low_bound) == INTEGER_CST + && tree_int_cst_sgn (low_bound) == -1) + { + error_at (OMP_CLAUSE_LOCATION (c), + "negative low bound in array section in %qs clause", + omp_clause_code_name[OMP_CLAUSE_CODE (c)]); + return error_mark_node; + } + if (length != NULL_TREE + && TREE_CODE (length) == INTEGER_CST + && tree_int_cst_sgn (length) == -1) + { + error_at (OMP_CLAUSE_LOCATION (c), + "negative length in array section in %qs clause", + omp_clause_code_name[OMP_CLAUSE_CODE (c)]); + return error_mark_node; + } + if (TYPE_DOMAIN (type) + && TYPE_MAX_VALUE (TYPE_DOMAIN (type)) + && TREE_CODE (TYPE_MAX_VALUE (TYPE_DOMAIN (type))) + == INTEGER_CST) + { + tree size = size_binop (PLUS_EXPR, + TYPE_MAX_VALUE (TYPE_DOMAIN (type)), + size_one_node); + if (TREE_CODE (low_bound) == INTEGER_CST) + { + if (tree_int_cst_lt (size, low_bound)) + { + error_at (OMP_CLAUSE_LOCATION (c), + "low bound %qE above array section size " + "in %qs clause", low_bound, + omp_clause_code_name[OMP_CLAUSE_CODE (c)]); + return error_mark_node; + } + if (tree_int_cst_equal (size, low_bound)) + maybe_zero_len = true; + else if (length == NULL_TREE + && first_non_one == types.length () + && tree_int_cst_equal + (TYPE_MAX_VALUE (TYPE_DOMAIN (type)), + low_bound)) + first_non_one++; + } + else if (length == NULL_TREE) + { + maybe_zero_len = true; + if (first_non_one == types.length ()) + first_non_one++; + } + if (length && TREE_CODE (length) == INTEGER_CST) + { + if (tree_int_cst_lt (size, length)) + { + error_at (OMP_CLAUSE_LOCATION (c), + "length %qE above array section size " + "in %qs clause", length, + omp_clause_code_name[OMP_CLAUSE_CODE (c)]); + return error_mark_node; + } + if (TREE_CODE (low_bound) == INTEGER_CST) + { + tree lbpluslen + = size_binop (PLUS_EXPR, + fold_convert (sizetype, low_bound), + fold_convert (sizetype, length)); + if (TREE_CODE (lbpluslen) == INTEGER_CST + && tree_int_cst_lt (size, lbpluslen)) + { + error_at (OMP_CLAUSE_LOCATION (c), + "high bound %qE above array section size " + "in %qs clause", lbpluslen, + omp_clause_code_name[OMP_CLAUSE_CODE (c)]); + return error_mark_node; + } + } + } + } + else if (length == NULL_TREE) + { + maybe_zero_len = true; + if (first_non_one == types.length ()) + first_non_one++; + } + + /* For [lb:] we will need to evaluate lb more than once. */ + if (length == NULL_TREE && OMP_CLAUSE_CODE (c) != OMP_CLAUSE_DEPEND) + { + tree lb = c_save_expr (low_bound); + if (lb != low_bound) + { + TREE_PURPOSE (t) = lb; + low_bound = lb; + } + } + } + else if (TREE_CODE (type) == POINTER_TYPE) + { + if (length == NULL_TREE) + { + error_at (OMP_CLAUSE_LOCATION (c), + "for pointer type length expression is not optional"); + return error_mark_node; + } + /* If there is a pointer type anywhere but in the very first + array-section-subscript, the array section can't be contiguous. */ + if (OMP_CLAUSE_CODE (c) != OMP_CLAUSE_DEPEND + && TREE_CODE (TREE_CHAIN (t)) == TREE_LIST) + { + error_at (OMP_CLAUSE_LOCATION (c), + "array section is not contiguous in %qs clause", + omp_clause_code_name[OMP_CLAUSE_CODE (c)]); + return error_mark_node; + } + } + else + { + error_at (OMP_CLAUSE_LOCATION (c), + "%qE does not have pointer or array type", ret); + return error_mark_node; + } + if (OMP_CLAUSE_CODE (c) != OMP_CLAUSE_DEPEND) + types.safe_push (TREE_TYPE (ret)); + /* For pointer based array sections we will need to evaluate lb more + than once. */ + if (pointer_based_p) + { + tree lb = c_save_expr (low_bound); + if (lb != low_bound) + { + TREE_PURPOSE (t) = lb; + low_bound = lb; + } + } + ret = build_array_ref (OMP_CLAUSE_LOCATION (c), ret, low_bound); + return ret; +} + +/* Handle array sections for clause C. */ + +static bool +handle_omp_array_sections (tree c) +{ + bool maybe_zero_len = false; + bool pointer_based_p = false; + unsigned int first_non_one = 0; + vec types = vNULL; + tree first = handle_omp_array_sections_1 (c, OMP_CLAUSE_DECL (c), types, + maybe_zero_len, first_non_one, + pointer_based_p); + if (first == error_mark_node) + { + types.release (); + return true; + } + if (first == NULL_TREE) + { + types.release (); + return false; + } + if (OMP_CLAUSE_CODE (c) == OMP_CLAUSE_DEPEND) + { + tree t = OMP_CLAUSE_DECL (c); + tree tem = NULL_TREE; + types.release (); + /* Need to evaluate side effects in the length expressions + if any. */ + while (TREE_CODE (t) == TREE_LIST) + { + if (TREE_VALUE (t) && TREE_SIDE_EFFECTS (TREE_VALUE (t))) + { + if (tem == NULL_TREE) + tem = TREE_VALUE (t); + else + tem = build2 (COMPOUND_EXPR, TREE_TYPE (tem), + TREE_VALUE (t), tem); + } + t = TREE_CHAIN (t); + } + if (tem) + first = build2 (COMPOUND_EXPR, TREE_TYPE (first), tem, first); + OMP_CLAUSE_DECL (c) = first; + } + else + { + unsigned int num = types.length (), i; + tree t, side_effects = NULL_TREE, size = NULL_TREE; + tree condition = NULL_TREE; + + if (int_size_in_bytes (TREE_TYPE (first)) <= 0) + maybe_zero_len = true; + + for (i = num, t = OMP_CLAUSE_DECL (c); i > 0; + t = TREE_CHAIN (t)) + { + tree low_bound = TREE_PURPOSE (t); + tree length = TREE_VALUE (t); + + i--; + if (low_bound + && TREE_CODE (low_bound) == INTEGER_CST + && TYPE_PRECISION (TREE_TYPE (low_bound)) + > TYPE_PRECISION (sizetype)) + low_bound = fold_convert (sizetype, low_bound); + if (length + && TREE_CODE (length) == INTEGER_CST + && TYPE_PRECISION (TREE_TYPE (length)) + > TYPE_PRECISION (sizetype)) + length = fold_convert (sizetype, length); + if (low_bound == NULL_TREE) + low_bound = integer_zero_node; + if (!maybe_zero_len && i > first_non_one) + { + if (integer_nonzerop (low_bound)) + goto do_warn_noncontiguous; + if (length != NULL_TREE + && TREE_CODE (length) == INTEGER_CST + && TYPE_DOMAIN (types[i]) + && TYPE_MAX_VALUE (TYPE_DOMAIN (types[i])) + && TREE_CODE (TYPE_MAX_VALUE (TYPE_DOMAIN (types[i]))) + == INTEGER_CST) + { + tree size; + size = size_binop (PLUS_EXPR, + TYPE_MAX_VALUE (TYPE_DOMAIN (types[i])), + size_one_node); + if (!tree_int_cst_equal (length, size)) + { + do_warn_noncontiguous: + error_at (OMP_CLAUSE_LOCATION (c), + "array section is not contiguous in %qs " + "clause", + omp_clause_code_name[OMP_CLAUSE_CODE (c)]); + types.release (); + return true; + } + } + if (length != NULL_TREE + && TREE_SIDE_EFFECTS (length)) + { + if (side_effects == NULL_TREE) + side_effects = length; + else + side_effects = build2 (COMPOUND_EXPR, + TREE_TYPE (side_effects), + length, side_effects); + } + } + else + { + tree l; + + if (i > first_non_one && length && integer_nonzerop (length)) + continue; + if (length) + l = fold_convert (sizetype, length); + else + { + l = size_binop (PLUS_EXPR, + TYPE_MAX_VALUE (TYPE_DOMAIN (types[i])), + size_one_node); + l = size_binop (MINUS_EXPR, l, + fold_convert (sizetype, low_bound)); + } + if (i > first_non_one) + { + l = fold_build2 (NE_EXPR, boolean_type_node, l, + size_zero_node); + if (condition == NULL_TREE) + condition = l; + else + condition = fold_build2 (BIT_AND_EXPR, boolean_type_node, + l, condition); + } + else if (size == NULL_TREE) + { + size = size_in_bytes (TREE_TYPE (types[i])); + size = size_binop (MULT_EXPR, size, l); + if (condition) + size = fold_build3 (COND_EXPR, sizetype, condition, + size, size_zero_node); + } + else + size = size_binop (MULT_EXPR, size, l); + } + } + types.release (); + if (side_effects) + size = build2 (COMPOUND_EXPR, sizetype, side_effects, size); + OMP_CLAUSE_DECL (c) = first; + OMP_CLAUSE_SIZE (c) = size; + if (pointer_based_p) + { + tree c2 = build_omp_clause (OMP_CLAUSE_LOCATION (c), OMP_CLAUSE_MAP); + OMP_CLAUSE_MAP_KIND (c2) = OMP_CLAUSE_MAP_POINTER; + if (!c_mark_addressable (t)) + return false; + OMP_CLAUSE_DECL (c2) = t; + t = build_fold_addr_expr (first); + t = fold_convert_loc (OMP_CLAUSE_LOCATION (c), + build_pointer_type (char_type_node), t); + t = fold_build2_loc (OMP_CLAUSE_LOCATION (c), MINUS_EXPR, + ptrdiff_type_node, t, + fold_convert_loc (OMP_CLAUSE_LOCATION (c), + TREE_TYPE (t), + OMP_CLAUSE_DECL (c2))); + OMP_CLAUSE_SIZE (c2) = t; + OMP_CLAUSE_CHAIN (c2) = OMP_CLAUSE_CHAIN (c); + OMP_CLAUSE_CHAIN (c) = c2; + } + } + return false; +} + /* For all elements of CLAUSES, validate them vs OpenMP constraints. Remove any elements from the list that are invalid. */ @@ -10954,21 +11383,49 @@ c_finish_omp_clauses (tree clauses) case OMP_CLAUSE_DEPEND: t = OMP_CLAUSE_DECL (c); - /* FIXME: depend clause argument may be also array section. */ - if (TREE_CODE (t) != VAR_DECL && TREE_CODE (t) != PARM_DECL) + if (TREE_CODE (t) == TREE_LIST) + { + if (handle_omp_array_sections (c)) + remove = true; + break; + } + if (t == error_mark_node) + remove = true; + else if (TREE_CODE (t) != VAR_DECL && TREE_CODE (t) != PARM_DECL) { error_at (OMP_CLAUSE_LOCATION (c), "%qE is not a variable in % clause", t); remove = true; } + else if (!c_mark_addressable (t)) + remove = true; break; case OMP_CLAUSE_MAP: case OMP_CLAUSE_TO: case OMP_CLAUSE_FROM: t = OMP_CLAUSE_DECL (c); - /* FIXME: map clause argument may be also array section. */ - if (TREE_CODE (t) != VAR_DECL && TREE_CODE (t) != PARM_DECL) + if (TREE_CODE (t) == TREE_LIST) + { + if (handle_omp_array_sections (c)) + remove = true; + else + { + t = OMP_CLAUSE_DECL (c); + if (!COMPLETE_TYPE_P (TREE_TYPE (t))) + { + error_at (OMP_CLAUSE_LOCATION (c), + "array section does not have mappable type " + "in %qs clause", + omp_clause_code_name[OMP_CLAUSE_CODE (c)]); + remove = true; + } + } + break; + } + if (t == error_mark_node) + remove = true; + else if (TREE_CODE (t) != VAR_DECL && TREE_CODE (t) != PARM_DECL) { error_at (OMP_CLAUSE_LOCATION (c), "%qE is not a variable in %qs clause", t, @@ -10982,6 +11439,24 @@ c_finish_omp_clauses (tree clauses) omp_clause_code_name[OMP_CLAUSE_CODE (c)]); remove = true; } + else if (!c_mark_addressable (t)) + remove = true; + else if (!COMPLETE_TYPE_P (TREE_TYPE (t))) + { + error_at (OMP_CLAUSE_LOCATION (c), + "%qD does not have a mappable type in %qs clause", t, + omp_clause_code_name[OMP_CLAUSE_CODE (c)]); + remove = true; + } + else if (OMP_CLAUSE_CODE (c) == OMP_CLAUSE_MAP) + break; + else if (bitmap_bit_p (&generic_head, DECL_UID (t))) + { + error ("%qD appears more than once in motion clauses", t); + remove = true; + } + else + bitmap_set_bit (&generic_head, DECL_UID (t)); break; case OMP_CLAUSE_UNIFORM: @@ -11013,6 +11488,7 @@ c_finish_omp_clauses (tree clauses) case OMP_CLAUSE_IF: case OMP_CLAUSE_NUM_THREADS: + case OMP_CLAUSE_THREAD_LIMIT: case OMP_CLAUSE_SCHEDULE: case OMP_CLAUSE_ORDERED: case OMP_CLAUSE_DEFAULT: --- gcc/cp/parser.c.jj 2013-07-03 22:15:07.000000000 +0200 +++ gcc/cp/parser.c 2013-07-06 19:33:15.297030502 +0200 @@ -29745,6 +29745,36 @@ cp_parser_omp_declare_target (cp_parser static void cp_parser_omp_end_declare_target (cp_parser *parser, cp_token *pragma_tok) { + const char *p = ""; + if (cp_lexer_next_token_is (parser->lexer, CPP_NAME)) + { + tree id = cp_lexer_peek_token (parser->lexer)->u.value; + p = IDENTIFIER_POINTER (id); + } + if (strcmp (p, "declare") == 0) + { + cp_lexer_consume_token (parser->lexer); + p = ""; + if (cp_lexer_next_token_is (parser->lexer, CPP_NAME)) + { + tree id = cp_lexer_peek_token (parser->lexer)->u.value; + p = IDENTIFIER_POINTER (id); + } + if (strcmp (p, "target") == 0) + cp_lexer_consume_token (parser->lexer); + else + { + cp_parser_error (parser, "expected %"); + cp_parser_skip_to_pragma_eol (parser, pragma_tok); + return; + } + } + else + { + cp_parser_error (parser, "expected %"); + cp_parser_skip_to_pragma_eol (parser, pragma_tok); + return; + } cp_parser_skip_to_pragma_eol (parser, pragma_tok); if (!current_omp_declare_target_attribute) error_at (pragma_tok->location, @@ -29757,7 +29787,8 @@ cp_parser_omp_end_declare_target (cp_par /* OpenMP 4.0 #pragma omp declare simd declare-simd-clauses[optseq] new-line #pragma omp declare reduction (reduction-id : typename-list : expression) \ - identity-clause[opt] new-line */ + identity-clause[opt] new-line + #pragma omp declare target new-line */ static void cp_parser_omp_declare (cp_parser *parser, cp_token *pragma_tok, @@ -29790,7 +29821,8 @@ cp_parser_omp_declare (cp_parser *parser return; } } - cp_parser_error (parser, "expected % or %"); + cp_parser_error (parser, "expected % or % " + "or %"); cp_parser_require_pragma_eol (parser, pragma_tok); } --- gcc/testsuite/c-c++-common/gomp/depend-2.c.jj 2013-06-04 20:55:56.000000000 +0200 +++ gcc/testsuite/c-c++-common/gomp/depend-2.c 2013-07-06 19:18:19.474914134 +0200 @@ -1,4 +1,4 @@ -/* { dg-do compile { target c++ } } */ +/* { dg-do compile } */ /* { dg-options "-fopenmp" } */ void bar (int a[10][10][10]); --- gcc/testsuite/c-c++-common/gomp/map-1.c.jj 2013-06-04 20:55:56.000000000 +0200 +++ gcc/testsuite/c-c++-common/gomp/map-1.c 2013-07-06 19:18:46.161478820 +0200 @@ -1,4 +1,4 @@ -/* { dg-do compile { target c++ } } */ +/* { dg-do compile } */ /* { dg-options "-fopenmp" } */ extern int a[][10], a2[][10]; --- gcc/testsuite/c-c++-common/gomp/depend-1.c.jj 2013-06-04 20:55:56.000000000 +0200 +++ gcc/testsuite/c-c++-common/gomp/depend-1.c 2013-07-06 19:18:08.434094464 +0200 @@ -1,4 +1,4 @@ -/* { dg-do compile { target c++ } } */ +/* { dg-do compile } */ /* { dg-options "-fopenmp" } */ extern int a[][10], a2[][10]; --- gcc/c-family/c-pragma.h.jj 2013-06-14 18:46:39.000000000 +0200 +++ gcc/c-family/c-pragma.h 2013-07-06 18:32:58.451917415 +0200 @@ -33,42 +33,24 @@ typedef enum pragma_kind { PRAGMA_OMP_CANCELLATION_POINT, PRAGMA_OMP_CRITICAL, PRAGMA_OMP_DECLARE_REDUCTION, - PRAGMA_OMP_DECLARE_SIMD, - PRAGMA_OMP_DECLARE_TARGET, PRAGMA_OMP_DISTRIBUTE, - PRAGMA_OMP_DISTRIBUTE_PARALLEL_FOR, - PRAGMA_OMP_DISTRIBUTE_PARALLEL_FOR_SIMD, - PRAGMA_OMP_DISTRIBUTE_SIMD, PRAGMA_OMP_END_DECLARE_TARGET, PRAGMA_OMP_FLUSH, PRAGMA_OMP_FOR, - PRAGMA_OMP_FOR_SIMD, PRAGMA_OMP_MASTER, PRAGMA_OMP_ORDERED, PRAGMA_OMP_PARALLEL, - PRAGMA_OMP_PARALLEL_FOR, - PRAGMA_OMP_PARALLEL_FOR_SIMD, - PRAGMA_OMP_PARALLEL_SECTIONS, PRAGMA_OMP_SECTION, PRAGMA_OMP_SECTIONS, PRAGMA_OMP_SIMD, PRAGMA_OMP_SINGLE, PRAGMA_OMP_TARGET, - PRAGMA_OMP_TARGET_DATA, - PRAGMA_OMP_TARGET_TEAMS, - PRAGMA_OMP_TARGET_TEAMS_DISTRIBUTE, - PRAGMA_OMP_TARGET_TEAMS_DISTRIBUTE_PARALLEL_FOR, - PRAGMA_OMP_TARGET_TEAMS_DISTRIBUTE_PARALLEL_FOR_SIMD, - PRAGMA_OMP_TARGET_UPDATE, PRAGMA_OMP_TASK, PRAGMA_OMP_TASKGROUP, PRAGMA_OMP_TASKWAIT, PRAGMA_OMP_TASKYIELD, PRAGMA_OMP_THREADPRIVATE, PRAGMA_OMP_TEAMS, - PRAGMA_OMP_TEAMS_DISTRIBUTE, - PRAGMA_OMP_TEAMS_DISTRIBUTE_PARALLEL_FOR, - PRAGMA_OMP_TEAMS_DISTRIBUTE_PARALLEL_FOR_SIMD, PRAGMA_GCC_PCH_PREPROCESS, --- libgomp/testsuite/libgomp.c/for-3.c.jj 2013-07-06 19:43:08.307165397 +0200 +++ libgomp/testsuite/libgomp.c/for-3.c 2013-07-06 19:44:29.618818923 +0200 @@ -0,0 +1,113 @@ +/* { dg-options "-std=gnu99 -fopenmp" } */ + +extern void abort (); + +#define M(x, y, z) O(x, y, z) +#define O(x, y, z) x ## _ ## y ## _ ## z + +#pragma omp declare target + +#define F distribute +#define G d +#define S +#define N(x) M(x, G, normal) +#include "for-2.h" +#undef S +#undef N +#undef F +#undef G + +#define F distribute +#define G d_ds128 +#define S dist_schedule(static, 128) +#define N(x) M(x, G, normal) +#include "for-2.h" +#undef S +#undef N +#undef F +#undef G + +#define F distribute simd +#define G ds +#define S +#define N(x) M(x, G, normal) +#include "for-2.h" +#undef S +#undef N +#undef F +#undef G + +#define F distribute simd +#define G ds_ds128 +#define S dist_schedule(static, 128) +#define N(x) M(x, G, normal) +#include "for-2.h" +#undef S +#undef N +#undef F +#undef G + +#define F distribute parallel for +#define G dpf +#include "for-1.h" +#undef F +#undef G + +#define F distribute parallel for dist_schedule(static, 128) +#define G dpf_ds128 +#include "for-1.h" +#undef F +#undef G + +#define F distribute parallel for simd +#define G dpfs +#include "for-1.h" +#undef F +#undef G + +#define F distribute parallel for simd dist_schedule(static, 128) +#define G dpfs_ds128 +#include "for-1.h" +#undef F +#undef G + +#pragma omp end declare target + +int +main () +{ + int err = 0; +/* FIXME: distribute construct must be closely nested + in teams region, but we don't handle target expansions + yet. Enable when it works. */ +/* #pragma omp target teams reduction(|:err) */ + { + err |= test_d_normal (); + err |= test_d_ds128_normal (); + err |= test_ds_normal (); + err |= test_ds_ds128_normal (); + err |= test_dpf_static (); + err |= test_dpf_static32 (); + err |= test_dpf_auto (); + err |= test_dpf_guided32 (); + err |= test_dpf_runtime (); + err |= test_dpf_ds128_static (); + err |= test_dpf_ds128_static32 (); + err |= test_dpf_ds128_auto (); + err |= test_dpf_ds128_guided32 (); + err |= test_dpf_ds128_runtime (); + err |= test_dpfs_static (); + err |= test_dpfs_static32 (); + err |= test_dpfs_auto (); + err |= test_dpfs_guided32 (); + err |= test_dpfs_runtime (); + err |= test_dpfs_ds128_static (); + err |= test_dpfs_ds128_static32 (); + err |= test_dpfs_ds128_auto (); + err |= test_dpfs_ds128_guided32 (); + err |= test_dpfs_ds128_runtime (); + } + if (err) + abort (); + return 0; +} --- libgomp/testsuite/libgomp.c/simd-1.c.jj 2013-07-06 19:41:20.872945458 +0200 +++ libgomp/testsuite/libgomp.c/simd-1.c 2013-07-06 20:22:41.110996196 +0200 @@ -0,0 +1,57 @@ +/* { dg-do run } */ +/* { dg-options "-O2" } */ +/* { dg-additional-options "-msse2" { target sse2_runtime } } */ +/* { dg-additional-options "-mavx" { target avx_runtime } } */ + +extern void abort (); +int a[1024] __attribute__((aligned (32))) = { 1 }; +int b[1024] __attribute__((aligned (32))) = { 1 }; +int k, m; +struct U { int u; }; +struct V { int v; }; + +__attribute__((noinline, noclone)) int +foo (int *p) +{ + int i, s = 0; + struct U u; + struct V v; + #pragma omp simd aligned(a, p : 32) linear(k: m + 1) \ + reduction(+:s) lastprivate(u, v) + for (i = 0; i < 1024; i++) + { + a[i] *= p[i]; + u.u = p[i] + k; + k += m + 1; + v.v = p[i] + k; + s += p[i] + k; + } + if (u.u != 36 + 4 + 3 * 1023 || v.v != 36 + 4 + 3 * 1024) + abort (); + return s; +} + +int +main () +{ +#if __SIZEOF_INT__ >= 4 + int i; + k = 4; + m = 2; + for (i = 0; i < 1024; i++) + { + a[i] = i - 512; + b[i] = (i - 51) % 39; + } + int s = foo (b); + for (i = 0; i < 1024; i++) + { + if (b[i] != (i - 51) % 39 + || a[i] != (i - 512) * b[i]) + abort (); + } + if (k != 4 + 3 * 1024 || s != 1596127) + abort (); +#endif + return 0; +} --- libgomp/testsuite/libgomp.c/simd-2.c.jj 2013-07-06 19:41:23.902895215 +0200 +++ libgomp/testsuite/libgomp.c/simd-2.c 2013-07-06 19:47:08.878746011 +0200 @@ -0,0 +1,36 @@ +/* { dg-do run } */ +/* { dg-options "-O2" } */ +/* { dg-additional-options "-msse2" { target sse2_runtime } } */ +/* { dg-additional-options "-mavx" { target avx_runtime } } */ + +extern void abort (); +__UINTPTR_TYPE__ arr[1027]; + +__attribute__((noinline, noclone)) void +foo () +{ + int i, v; + #pragma omp simd private (v) safelen(16) + for (i = 0; i < 1027; i++) + arr[i] = (__UINTPTR_TYPE__) &v; +} + +int +main () +{ + int i, j, cnt = 0; + __UINTPTR_TYPE__ arr2[16]; + foo (); + for (i = 0; i < 1027; i++) + { + for (j = 0; j < cnt; j++) + if (arr[i] == arr2[j]) + break; + if (j != cnt) + continue; + if (cnt == 16) + abort (); + arr2[cnt++] = arr[i]; + } + return 0; +} --- libgomp/testsuite/libgomp.c/simd-3.c.jj 2013-07-06 19:41:26.916845206 +0200 +++ libgomp/testsuite/libgomp.c/simd-3.c 2013-07-06 19:48:02.498396227 +0200 @@ -0,0 +1,131 @@ +/* { dg-do run } */ +/* { dg-options "-O2" } */ +/* { dg-additional-options "-msse2" { target sse2_runtime } } */ +/* { dg-additional-options "-mavx" { target avx_runtime } } */ + +extern void abort (); +int a[1024] __attribute__((aligned (32))) = { 1 }; +int b[1024] __attribute__((aligned (32))) = { 1 }; +unsigned char c[1024] __attribute__((aligned (32))) = { 1 }; +int k, m; +__UINTPTR_TYPE__ u, u2, u3; + +__attribute__((noinline, noclone)) int +foo (int *p) +{ + int i, s = 0, s2 = 0, t, t2; + #pragma omp simd aligned(a, b, p : 32) linear(k: m + 1) reduction(+:s) \ + lastprivate (t2) + for (i = 0; i < 512; i++) + { + a[i] *= p[i]; + t2 = k + p[i]; + k += m + 1; + s += p[i] + k; + c[i]++; + } + #pragma omp simd aligned(a, b, p : 32) linear(k: m + 1) reduction(+:s2) \ + lastprivate (t, u, u2, u3) + for (i = 512; i < 1024; i++) + { + a[i] *= p[i]; + k += m + 1; + t = k + p[i]; + u = (__UINTPTR_TYPE__) &k; + u2 = (__UINTPTR_TYPE__) &s2; + u3 = (__UINTPTR_TYPE__) &t; + s2 += t; + c[i]++; + } + return s + s2 + t + t2; +} + +__attribute__((noinline, noclone)) long int +bar (int *p, long int n, long int o) +{ + long int i, s = 0, s2 = 0, t, t2; + #pragma omp simd aligned(a, b, p : 32) linear(k: m + 1) reduction(+:s) \ + lastprivate (t2) + for (i = 0; i < n; i++) + { + a[i] *= p[i]; + t2 = k + p[i]; + k += m + 1; + s += p[i] + k; + c[i]++; + } + #pragma omp simd aligned(a, b, p : 32) linear(k: m + 1) reduction(+:s2) \ + lastprivate (t, u, u2, u3) + for (i = n; i < o; i++) + { + a[i] *= p[i]; + k += m + 1; + t = k + p[i]; + u = (__UINTPTR_TYPE__) &k; + u2 = (__UINTPTR_TYPE__) &s2; + u3 = (__UINTPTR_TYPE__) &t; + s2 += t; + c[i]++; + } + return s + s2 + t + t2; +} + +int +main () +{ +#if __SIZEOF_INT__ >= 4 + int i; + k = 4; + m = 2; + for (i = 0; i < 1024; i++) + { + a[i] = i - 512; + b[i] = (i - 51) % 39; + c[i] = (unsigned char) i; + } + int s = foo (b); + for (i = 0; i < 1024; i++) + { + if (b[i] != (i - 51) % 39 + || a[i] != (i - 512) * b[i] + || c[i] != (unsigned char) (i + 1)) + abort (); + a[i] = i - 512; + } + if (k != 4 + 3 * 1024 + || s != 1596127 + (4 + 3 * 511 + b[511]) + (4 + 3 * 1024 + b[1023])) + abort (); + k = 4; + s = bar (b, 512, 1024); + for (i = 0; i < 1024; i++) + { + if (b[i] != (i - 51) % 39 + || a[i] != (i - 512) * b[i] + || c[i] != (unsigned char) (i + 2)) + abort (); + a[i] = i - 512; + } + if (k != 4 + 3 * 1024 + || s != 1596127 + (4 + 3 * 511 + b[511]) + (4 + 3 * 1024 + b[1023])) + abort (); + k = 4; + s = bar (b, 511, 1021); + for (i = 0; i < 1021; i++) + { + if (b[i] != (i - 51) % 39 + || a[i] != (i - 512) * b[i] + || c[i] != (unsigned char) (i + 3)) + abort (); + a[i] = i - 512; + } + for (i = 1021; i < 1024; i++) + if (b[i] != (i - 51) % 39 + || a[i] != i - 512 + || c[i] != (unsigned char) (i + 2)) + abort (); + if (k != 4 + 3 * 1021 + || s != 1586803 + (4 + 3 * 510 + b[510]) + (4 + 3 * 1021 + b[1020])) + abort (); +#endif + return 0; +}