From patchwork Wed Sep 18 11:38:27 2013 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: Jakub Jelinek X-Patchwork-Id: 275685 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 did not present a certificate) by ozlabs.org (Postfix) with ESMTPS id 6DE512C00F0 for ; Wed, 18 Sep 2013 21:38:45 +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=OmLtiD7tdONFMNBsdYcAoWmyGftF2 bB0jb92rFkMEZXaFSUaKUzUetuvW1HIK1DFHHgOGPtIDcEN50Gai7c05+IU2B2aT Z3RhIE0Esd4wYmVqDoPDmeeq30WMcY5CUTiyu3GMS7PeVjTejUHI7QoXiupDafKH WIokO3YbQa1qD8= 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=Iz4roqsrkx5piizmhns9eEKACkc=; b=aEF xnV7n+rb7osmQ0dHxPutEnIA55wg8znC3T18sHBQqvcMGx/gD4CiKnbr2ilog8Ve i3uKh16pahWE+Um3rEoA0F/TbN3ABRTYkUEuZ2/UaHh4+J3l35YqA7PU7Mnz5vDg 9vVfXkkJBsY0ZWIvNdaaQ9CdyVgnYCLh4jiNWIgw= Received: (qmail 25690 invoked by alias); 18 Sep 2013 11:38:38 -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 25677 invoked by uid 89); 18 Sep 2013 11:38:37 -0000 Received: from mx1.redhat.com (HELO mx1.redhat.com) (209.132.183.28) by sourceware.org (qpsmtpd/0.93/v0.84-503-g423c35a) with ESMTP; Wed, 18 Sep 2013 11:38:37 +0000 Authentication-Results: sourceware.org; auth=none X-Virus-Found: No X-Spam-SWARE-Status: No, score=-2.2 required=5.0 tests=AWL, BAYES_00, KAM_STOCKGEN, RP_MATCHES_RCVD autolearn=no version=3.3.2 X-HELO: mx1.redhat.com Received: from int-mx01.intmail.prod.int.phx2.redhat.com (int-mx01.intmail.prod.int.phx2.redhat.com [10.5.11.11]) by mx1.redhat.com (8.14.4/8.14.4) with ESMTP id r8IBcVLh027135 (version=TLSv1/SSLv3 cipher=DHE-RSA-AES256-SHA bits=256 verify=OK); Wed, 18 Sep 2013 07:38:31 -0400 Received: from tucnak.zalov.cz (vpn1-5-4.ams2.redhat.com [10.36.5.4]) by int-mx01.intmail.prod.int.phx2.redhat.com (8.13.8/8.13.8) with ESMTP id r8IBcSW9021433 (version=TLSv1/SSLv3 cipher=DHE-RSA-AES256-SHA bits=256 verify=NO); Wed, 18 Sep 2013 07:38:30 -0400 Received: from tucnak.zalov.cz (localhost [127.0.0.1]) by tucnak.zalov.cz (8.14.7/8.14.7) with ESMTP id r8IBcS09002683; Wed, 18 Sep 2013 13:38:28 +0200 Received: (from jakub@localhost) by tucnak.zalov.cz (8.14.7/8.14.7/Submit) id r8IBcRTW002682; Wed, 18 Sep 2013 13:38:27 +0200 Date: Wed, 18 Sep 2013 13:38:27 +0200 From: Jakub Jelinek To: "Joseph S. Myers" Cc: gcc-patches@gcc.gnu.org Subject: [gomp4] C UDR support Message-ID: <20130918113827.GM1817@tucnak.redhat.com> Reply-To: Jakub Jelinek MIME-Version: 1.0 Content-Disposition: inline User-Agent: Mutt/1.5.21 (2010-09-15) X-IsSubscribed: yes Hi! This is the C FE counterpart of the C++ FE OpenMP 4.0 user defined reductions, as C has no templates, class inheritance, doesn't allow #pragma omp declare reduction in structs/unions, the implementation is significantly simpler. Joseph, any comments on this? 2013-09-18 Jakub Jelinek * c-tree.h (c_omp_reduction_id, c_omp_reduction_decl, c_omp_reduction_lookup, c_check_omp_declare_reduction_r): New prototypes. * c-typeck.c: Include tree-inline.h. (c_clone_udr, c_find_omp_placeholder_r): New functions. (c_finish_omp_clauses): Handle user defined reductions. * Make-lang.in (c-typeck.o): Depend on $(TREE_INLINE_H). * c-parser.c (c_parser_omp_clause_reduction): Handle user defined reductions. (c_parser_omp_declare_reduction): New function. (c_parser_omp_declare): Call it. * c-decl.c (c_omp_reduction_id, c_omp_reduction_decl, c_omp_reduction_lookup, c_check_omp_declare_reduction_r): New functions. gcc/testsuite/ * gcc.dg/gomp/udr-1.c: New test. * gcc.dg/gomp/udr-2.c: New test. * gcc.dg/gomp/udr-3.c: New test. * gcc.dg/gomp/udr-4.c: New test. * gcc.dg/gomp/clause-1.c: Adjust error messages. libgomp/ * testsuite/libgomp.c/simd-4.c: New test. * testsuite/libgomp.c/simd-5.c: New test. * testsuite/libgomp.c/udr-1.c: New test. * testsuite/libgomp.c/udr-2.c: New test. * testsuite/libgomp.c/udr-3.c: New test. * testsuite/libgomp.c++/udr-9.C: New test. Jakub --- gcc/c/c-tree.h.jj 2013-09-18 12:06:04.051769378 +0200 +++ gcc/c/c-tree.h 2013-09-18 13:07:50.792969161 +0200 @@ -670,6 +670,10 @@ extern enum machine_mode c_default_point /* In c-decl.c */ extern void c_finish_incomplete_decl (tree); extern void c_write_global_declarations (void); +extern tree c_omp_reduction_id (enum tree_code, tree); +extern tree c_omp_reduction_decl (tree); +extern tree c_omp_reduction_lookup (tree, tree); +extern tree c_check_omp_declare_reduction_r (tree *, int *, void *); /* In c-errors.c */ extern void pedwarn_c90 (location_t, int opt, const char *, ...) ATTRIBUTE_GCC_DIAG(3,4); --- gcc/c/c-typeck.c.jj 2013-09-18 12:17:36.814044593 +0200 +++ gcc/c/c-typeck.c 2013-09-18 13:07:50.795968751 +0200 @@ -37,6 +37,7 @@ along with GCC; see the file COPYING3. #include "tree-iterator.h" #include "bitmap.h" #include "gimple.h" +#include "tree-inline.h" #include "c-family/c-objc.h" #include "c-family/c-common.h" #include "c-family/c-ubsan.h" @@ -11209,6 +11210,48 @@ handle_omp_array_sections (tree c) return false; } +/* Helper function of finish_omp_clauses. Clone STMT as if we were making + an inline call. But, remap + the OMP_DECL1 VAR_DECL (omp_out resp. omp_orig) to PLACEHOLDER + and OMP_DECL2 VAR_DECL (omp_in resp. omp_priv) to DECL. */ + +static tree +c_clone_omp_udr (tree stmt, tree omp_decl1, tree omp_decl2, + tree decl, tree placeholder) +{ + copy_body_data id; + struct pointer_map_t *decl_map = pointer_map_create (); + + *pointer_map_insert (decl_map, omp_decl1) = placeholder; + *pointer_map_insert (decl_map, omp_decl2) = decl; + memset (&id, 0, sizeof (id)); + id.src_fn = DECL_CONTEXT (omp_decl1); + id.dst_fn = current_function_decl; + id.src_cfun = DECL_STRUCT_FUNCTION (id.src_fn); + id.decl_map = decl_map; + + id.copy_decl = copy_decl_no_change; + id.transform_call_graph_edges = CB_CGE_DUPLICATE; + id.transform_new_cfg = true; + id.transform_return_to_modify = false; + id.transform_lang_insert_block = NULL; + id.eh_lp_nr = 0; + walk_tree (&stmt, copy_tree_body_r, &id, NULL); + pointer_map_destroy (decl_map); + return stmt; +} + +/* Helper function of c_finish_omp_clauses, called via walk_tree. + Find OMP_CLAUSE_PLACEHOLDER (passed in DATA) in *TP. */ + +static tree +c_find_omp_placeholder_r (tree *tp, int *, void *data) +{ + if (*tp == (tree) data) + return *tp; + return NULL_TREE; +} + /* For all elements of CLAUSES, validate them vs OpenMP constraints. Remove any elements from the list that are invalid. */ @@ -11252,14 +11295,8 @@ c_finish_omp_clauses (tree clauses) name = "reduction"; need_implicitly_determined = true; t = OMP_CLAUSE_DECL (c); - if (AGGREGATE_TYPE_P (TREE_TYPE (t)) - || POINTER_TYPE_P (TREE_TYPE (t))) - { - error_at (OMP_CLAUSE_LOCATION (c), - "%qE has invalid type for %", t); - remove = true; - } - else if (FLOAT_TYPE_P (TREE_TYPE (t))) + if (OMP_CLAUSE_REDUCTION_PLACEHOLDER (c) == NULL_TREE + && FLOAT_TYPE_P (TREE_TYPE (t))) { enum tree_code r_code = OMP_CLAUSE_REDUCTION_CODE (c); const char *r_name = NULL; @@ -11298,6 +11335,73 @@ c_finish_omp_clauses (tree clauses) remove = true; } } + else if (OMP_CLAUSE_REDUCTION_PLACEHOLDER (c) == error_mark_node) + { + error_at (OMP_CLAUSE_LOCATION (c), + "user defined reduction not found for %qD", t); + remove = true; + } + else if (OMP_CLAUSE_REDUCTION_PLACEHOLDER (c)) + { + tree list = OMP_CLAUSE_REDUCTION_PLACEHOLDER (c); + tree type = TYPE_MAIN_VARIANT (TREE_TYPE (t)); + tree placeholder = build_decl (OMP_CLAUSE_LOCATION (c), + VAR_DECL, NULL_TREE, type); + OMP_CLAUSE_REDUCTION_PLACEHOLDER (c) = placeholder; + DECL_ARTIFICIAL (placeholder) = 1; + DECL_IGNORED_P (placeholder) = 1; + if (TREE_ADDRESSABLE (TREE_VEC_ELT (list, 0))) + c_mark_addressable (placeholder); + if (TREE_ADDRESSABLE (TREE_VEC_ELT (list, 1))) + c_mark_addressable (OMP_CLAUSE_DECL (c)); + OMP_CLAUSE_REDUCTION_MERGE (c) + = c_clone_omp_udr (TREE_VEC_ELT (list, 2), + TREE_VEC_ELT (list, 0), + TREE_VEC_ELT (list, 1), + OMP_CLAUSE_DECL (c), placeholder); + OMP_CLAUSE_REDUCTION_MERGE (c) + = build3_loc (OMP_CLAUSE_LOCATION (c), BIND_EXPR, + void_type_node, NULL_TREE, + OMP_CLAUSE_REDUCTION_MERGE (c), NULL_TREE); + TREE_SIDE_EFFECTS (OMP_CLAUSE_REDUCTION_MERGE (c)) = 1; + if (TREE_VEC_LENGTH (list) == 6) + { + if (TREE_ADDRESSABLE (TREE_VEC_ELT (list, 3))) + c_mark_addressable (OMP_CLAUSE_DECL (c)); + if (TREE_ADDRESSABLE (TREE_VEC_ELT (list, 4))) + c_mark_addressable (placeholder); + tree init = TREE_VEC_ELT (list, 5); + if (init == error_mark_node) + init = DECL_INITIAL (TREE_VEC_ELT (list, 3)); + OMP_CLAUSE_REDUCTION_INIT (c) + = c_clone_omp_udr (init, TREE_VEC_ELT (list, 4), + TREE_VEC_ELT (list, 3), + OMP_CLAUSE_DECL (c), placeholder); + if (TREE_VEC_ELT (list, 5) == error_mark_node) + OMP_CLAUSE_REDUCTION_INIT (c) + = build2 (INIT_EXPR, TREE_TYPE (t), t, + OMP_CLAUSE_REDUCTION_INIT (c)); + if (walk_tree (&OMP_CLAUSE_REDUCTION_INIT (c), + c_find_omp_placeholder_r, + placeholder, NULL)) + OMP_CLAUSE_REDUCTION_OMP_ORIG_REF (c) = 1; + } + else + { + tree init; + if (AGGREGATE_TYPE_P (TREE_TYPE (t))) + init = build_constructor (TREE_TYPE (t), NULL); + else + init = fold_convert (TREE_TYPE (t), integer_zero_node); + OMP_CLAUSE_REDUCTION_INIT (c) + = build2 (INIT_EXPR, TREE_TYPE (t), t, init); + } + OMP_CLAUSE_REDUCTION_INIT (c) + = build3_loc (OMP_CLAUSE_LOCATION (c), BIND_EXPR, + void_type_node, NULL_TREE, + OMP_CLAUSE_REDUCTION_INIT (c), NULL_TREE); + TREE_SIDE_EFFECTS (OMP_CLAUSE_REDUCTION_INIT (c)) = 1; + } goto check_dup_generic; case OMP_CLAUSE_COPYPRIVATE: --- gcc/c/c-parser.c.jj 2013-09-18 12:06:03.995769689 +0200 +++ gcc/c/c-parser.c 2013-09-18 13:07:50.798968362 +0200 @@ -9688,7 +9688,13 @@ c_parser_omp_clause_private (c_parser *p OpenMP 3.1: reduction-operator: - One of: + * - & ^ | && || max min */ + One of: + * - & ^ | && || max min + + OpenMP 4.0: + + reduction-operator: + One of: + * - & ^ | && || + identifier */ static tree c_parser_omp_clause_reduction (c_parser *parser, tree list) @@ -9696,7 +9702,8 @@ c_parser_omp_clause_reduction (c_parser location_t clause_loc = c_parser_peek_token (parser)->location; if (c_parser_require (parser, CPP_OPEN_PAREN, "expected %<(%>")) { - enum tree_code code; + enum tree_code code = ERROR_MARK; + tree reduc_id = NULL_TREE; switch (c_parser_peek_token (parser)->type) { @@ -9738,8 +9745,9 @@ c_parser_omp_clause_reduction (c_parser code = MAX_EXPR; break; } + reduc_id = c_parser_peek_token (parser)->value; + break; } - /* FALLTHRU */ default: c_parser_error (parser, "expected %<+%>, %<*%>, %<-%>, %<&%>, " @@ -9748,6 +9756,7 @@ c_parser_omp_clause_reduction (c_parser return list; } c_parser_consume_token (parser); + reduc_id = c_omp_reduction_id (code, reduc_id); if (c_parser_require (parser, CPP_COLON, "expected %<:%>")) { tree nl, c; @@ -9755,7 +9764,17 @@ c_parser_omp_clause_reduction (c_parser nl = c_parser_omp_variable_list (parser, clause_loc, OMP_CLAUSE_REDUCTION, list); for (c = nl; c != list; c = OMP_CLAUSE_CHAIN (c)) - OMP_CLAUSE_REDUCTION_CODE (c) = code; + { + tree type = TREE_TYPE (OMP_CLAUSE_DECL (c)); + OMP_CLAUSE_REDUCTION_CODE (c) = code; + if (code == ERROR_MARK + || !(INTEGRAL_TYPE_P (type) + || TREE_CODE (type) == REAL_TYPE + || TREE_CODE (type) == COMPLEX_TYPE)) + OMP_CLAUSE_REDUCTION_PLACEHOLDER (c) + = c_omp_reduction_lookup (reduc_id, + TYPE_MAIN_VARIANT (type)); + } list = nl; } @@ -12430,10 +12449,357 @@ c_parser_omp_end_declare_target (c_parse current_omp_declare_target_attribute--; } + +/* OpenMP 4.0 + #pragma omp declare reduction (reduction-id : typename-list : expression) \ + initializer-clause[opt] new-line + + initializer-clause: + initializer (omp_priv = initializer) + initializer (function-name (argument-list)) */ + +static void +c_parser_omp_declare_reduction (c_parser *parser, enum pragma_context context) +{ + unsigned int tokens_avail = 0, i; + vec types = vNULL; + vec clauses = vNULL; + enum tree_code reduc_code = ERROR_MARK; + tree reduc_id = NULL_TREE; + tree type; + location_t rloc = c_parser_peek_token (parser)->location; + + if (context == pragma_struct || context == pragma_param) + { + error ("%<#pragma omp declare reduction%> not at file or block scope"); + goto fail; + } + + if (!c_parser_require (parser, CPP_OPEN_PAREN, "expected %<(%>")) + goto fail; + + switch (c_parser_peek_token (parser)->type) + { + case CPP_PLUS: + reduc_code = PLUS_EXPR; + break; + case CPP_MULT: + reduc_code = MULT_EXPR; + break; + case CPP_MINUS: + reduc_code = MINUS_EXPR; + break; + case CPP_AND: + reduc_code = BIT_AND_EXPR; + break; + case CPP_XOR: + reduc_code = BIT_XOR_EXPR; + break; + case CPP_OR: + reduc_code = BIT_IOR_EXPR; + break; + case CPP_AND_AND: + reduc_code = TRUTH_ANDIF_EXPR; + break; + case CPP_OR_OR: + reduc_code = TRUTH_ORIF_EXPR; + break; + case CPP_NAME: + const char *p; + p = IDENTIFIER_POINTER (c_parser_peek_token (parser)->value); + if (strcmp (p, "min") == 0) + { + reduc_code = MIN_EXPR; + break; + } + if (strcmp (p, "max") == 0) + { + reduc_code = MAX_EXPR; + break; + } + reduc_id = c_parser_peek_token (parser)->value; + break; + default: + c_parser_error (parser, + "expected %<+%>, %<*%>, %<-%>, %<&%>, " + "%<^%>, %<|%>, %<&&%>, %<||%>, % or identifier"); + goto fail; + } + + tree orig_reduc_id, reduc_decl; + orig_reduc_id = reduc_id; + reduc_id = c_omp_reduction_id (reduc_code, reduc_id); + reduc_decl = c_omp_reduction_decl (reduc_id); + c_parser_consume_token (parser); + + if (!c_parser_require (parser, CPP_COLON, "expected %<:%>")) + goto fail; + + while (true) + { + location_t loc = c_parser_peek_token (parser)->location; + struct c_type_name *ctype = c_parser_type_name (parser); + if (ctype != NULL) + { + type = groktypename (ctype, NULL, NULL); + if (type == error_mark_node) + ; + else if ((INTEGRAL_TYPE_P (type) + || TREE_CODE (type) == REAL_TYPE + || TREE_CODE (type) == COMPLEX_TYPE) + && orig_reduc_id == NULL_TREE) + error_at (loc, "predeclared arithmetic type in " + "%<#pragma omp declare reduction%>"); + else if (TREE_CODE (type) == FUNCTION_TYPE + || TREE_CODE (type) == ARRAY_TYPE) + error_at (loc, "function or array type in " + "%<#pragma omp declare reduction%>"); + else if (TYPE_QUALS_NO_ADDR_SPACE (type)) + error_at (loc, "const, volatile or restrict qualified type in " + "%<#pragma omp declare reduction%>"); + else + { + tree t; + for (t = DECL_INITIAL (reduc_decl); t; t = TREE_CHAIN (t)) + if (comptypes (TREE_PURPOSE (t), type)) + { + error_at (loc, "redeclaration of %qs " + "%<#pragma omp declare reduction%> for " + "type %qT", + IDENTIFIER_POINTER (reduc_id) + + sizeof ("omp declare reduction ") - 1, + type); + location_t ploc + = DECL_SOURCE_LOCATION (TREE_VEC_ELT (TREE_VALUE (t), + 0)); + error_at (ploc, "previous %<#pragma omp declare " + "reduction%>"); + break; + } + if (t == NULL_TREE) + types.safe_push (type); + } + if (c_parser_next_token_is (parser, CPP_COMMA)) + c_parser_consume_token (parser); + else + break; + } + else + break; + } + + if (!c_parser_require (parser, CPP_COLON, "expected %<:%>") + || types.is_empty ()) + { + fail: + clauses.release (); + types.release (); + while (true) + { + c_token *token = c_parser_peek_token (parser); + if (token->type == CPP_EOF || token->type == CPP_PRAGMA_EOL) + break; + c_parser_consume_token (parser); + } + c_parser_skip_to_pragma_eol (parser); + return; + } + + if (types.length () > 1) + { + while (c_parser_next_token_is_not (parser, CPP_PRAGMA_EOL)) + { + c_token *token = c_parser_peek_token (parser); + if (token->type == CPP_EOF) + goto fail; + clauses.safe_push (*token); + c_parser_consume_token (parser); + } + clauses.safe_push (*c_parser_peek_token (parser)); + c_parser_skip_to_pragma_eol (parser); + + /* Make sure nothing tries to read past the end of the tokens. */ + c_token eof_token; + memset (&eof_token, 0, sizeof (eof_token)); + eof_token.type = CPP_EOF; + clauses.safe_push (eof_token); + clauses.safe_push (eof_token); + } + + int errs = errorcount; + FOR_EACH_VEC_ELT (types, i, type) + { + tokens_avail = parser->tokens_avail; + gcc_assert (parser->tokens == &parser->tokens_buf[0]); + if (!clauses.is_empty ()) + { + parser->tokens = clauses.address (); + parser->tokens_avail = clauses.length (); + parser->in_pragma = true; + } + + bool nested = current_function_decl != NULL_TREE; + if (nested) + c_push_function_context (); + tree fndecl = build_decl (BUILTINS_LOCATION, FUNCTION_DECL, + reduc_id, default_function_type); + current_function_decl = fndecl; + allocate_struct_function (fndecl, true); + push_scope (); + tree stmt = push_stmt_list (); + /* Intentionally BUILTINS_LOCATION, so that -Wshadow doesn't + warn about these. */ + tree omp_out = build_decl (BUILTINS_LOCATION, VAR_DECL, + get_identifier ("omp_out"), type); + DECL_ARTIFICIAL (omp_out) = 1; + DECL_CONTEXT (omp_out) = fndecl; + pushdecl (omp_out); + tree omp_in = build_decl (BUILTINS_LOCATION, VAR_DECL, + get_identifier ("omp_in"), type); + DECL_ARTIFICIAL (omp_in) = 1; + DECL_CONTEXT (omp_in) = fndecl; + pushdecl (omp_in); + struct c_expr combiner = c_parser_expression (parser); + struct c_expr initializer; + tree omp_priv = NULL_TREE, omp_orig = NULL_TREE; + bool bad = false; + initializer.value = error_mark_node; + if (!c_parser_require (parser, CPP_CLOSE_PAREN, "expected %<)%>")) + bad = true; + else if (c_parser_next_token_is (parser, CPP_NAME) + && strcmp (IDENTIFIER_POINTER + (c_parser_peek_token (parser)->value), + "initializer") == 0) + { + c_parser_consume_token (parser); + pop_scope (); + push_scope (); + omp_priv = build_decl (BUILTINS_LOCATION, VAR_DECL, + get_identifier ("omp_priv"), type); + DECL_ARTIFICIAL (omp_priv) = 1; + DECL_INITIAL (omp_priv) = error_mark_node; + DECL_CONTEXT (omp_priv) = fndecl; + pushdecl (omp_priv); + omp_orig = build_decl (BUILTINS_LOCATION, VAR_DECL, + get_identifier ("omp_orig"), type); + DECL_ARTIFICIAL (omp_orig) = 1; + DECL_CONTEXT (omp_orig) = fndecl; + pushdecl (omp_orig); + if (!c_parser_require (parser, CPP_OPEN_PAREN, "expected %<(%>")) + bad = true; + else if (!c_parser_next_token_is (parser, CPP_NAME)) + { + c_parser_error (parser, "expected % or " + "function-name"); + bad = true; + } + else if (strcmp (IDENTIFIER_POINTER + (c_parser_peek_token (parser)->value), + "omp_priv") != 0) + { + if (c_parser_peek_2nd_token (parser)->type != CPP_OPEN_PAREN + || c_parser_peek_token (parser)->id_kind != C_ID_ID) + { + c_parser_error (parser, "expected function-name %<(%>"); + bad = true; + } + else + initializer = c_parser_postfix_expression (parser); + if (initializer.value + && TREE_CODE (initializer.value) == CALL_EXPR) + { + int j; + tree c = initializer.value; + for (j = 0; j < call_expr_nargs (c); j++) + if (TREE_CODE (CALL_EXPR_ARG (c, j)) == ADDR_EXPR + && TREE_OPERAND (CALL_EXPR_ARG (c, j), 0) == omp_priv) + break; + if (j == call_expr_nargs (c)) + error ("one of the initializer call arguments should be " + "%<&omp_priv%>"); + } + } + else + { + c_parser_consume_token (parser); + if (!c_parser_require (parser, CPP_EQ, "expected %<=%>")) + bad = true; + else + { + tree st = push_stmt_list (); + start_init (omp_priv, NULL_TREE, 0); + location_t loc = c_parser_peek_token (parser)->location; + struct c_expr init = c_parser_initializer (parser); + finish_init (); + finish_decl (omp_priv, loc, init.value, + init.original_type, NULL_TREE); + pop_stmt_list (st); + } + } + if (!bad + && !c_parser_require (parser, CPP_CLOSE_PAREN, "expected %<)%>")) + bad = true; + } + + if (!bad) + { + c_parser_skip_to_pragma_eol (parser); + + tree t = tree_cons (type, make_tree_vec (omp_priv ? 6 : 3), + DECL_INITIAL (reduc_decl)); + DECL_INITIAL (reduc_decl) = t; + DECL_SOURCE_LOCATION (omp_out) = rloc; + TREE_VEC_ELT (TREE_VALUE (t), 0) = omp_out; + TREE_VEC_ELT (TREE_VALUE (t), 1) = omp_in; + TREE_VEC_ELT (TREE_VALUE (t), 2) = combiner.value; + walk_tree (&combiner.value, c_check_omp_declare_reduction_r, + &TREE_VEC_ELT (TREE_VALUE (t), 0), NULL); + if (omp_priv) + { + DECL_SOURCE_LOCATION (omp_priv) = rloc; + TREE_VEC_ELT (TREE_VALUE (t), 3) = omp_priv; + TREE_VEC_ELT (TREE_VALUE (t), 4) = omp_orig; + TREE_VEC_ELT (TREE_VALUE (t), 5) = initializer.value; + walk_tree (&initializer.value, c_check_omp_declare_reduction_r, + &TREE_VEC_ELT (TREE_VALUE (t), 3), NULL); + walk_tree (&DECL_INITIAL (omp_priv), + c_check_omp_declare_reduction_r, + &TREE_VEC_ELT (TREE_VALUE (t), 3), NULL); + } + } + + pop_stmt_list (stmt); + pop_scope (); + if (cfun->language != NULL) + { + ggc_free (cfun->language); + cfun->language = NULL; + } + set_cfun (NULL); + current_function_decl = NULL_TREE; + if (nested) + c_pop_function_context (); + + if (!clauses.is_empty ()) + { + parser->tokens = &parser->tokens_buf[0]; + parser->tokens_avail = tokens_avail; + } + if (bad) + goto fail; + if (errs != errorcount) + break; + } + + clauses.release (); + types.release (); +} + + /* 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 + initializer-clause[opt] new-line #pragma omp declare target new-line */ static void @@ -12450,12 +12816,12 @@ c_parser_omp_declare (c_parser *parser, c_parser_omp_declare_simd (parser, context); return; } -/* if (strcmp (p, "reduction") == 0) + if (strcmp (p, "reduction") == 0) { c_parser_consume_token (parser); - c_parser_omp_declare_reduction (parser); + c_parser_omp_declare_reduction (parser, context); return; - } */ + } if (strcmp (p, "target") == 0) { c_parser_consume_token (parser); --- gcc/c/Make-lang.in.jj 2013-09-18 12:06:04.047769396 +0200 +++ gcc/c/Make-lang.in 2013-09-18 13:07:50.795968751 +0200 @@ -189,7 +189,7 @@ c/c-parser.o : c/c-parser.c $(CONFIG_H) c/c-typeck.o : c/c-typeck.c c/c-lang.h $(CONFIG_H) $(SYSTEM_H) coretypes.h $(TM_H) \ $(TREE_H) $(C_TREE_H) $(TARGET_H) $(FLAGS_H) intl.h \ - langhooks.h tree-iterator.h $(BITMAP_H) $(GIMPLE_H) \ + langhooks.h tree-iterator.h $(BITMAP_H) $(GIMPLE_H) $(TREE_INLINE_H) \ c-family/c-objc.h c-family/c-common.h c/c-array-notation.o: c/c-array-notation.c c/c-lang.h $(CONFIG_H) \ --- gcc/c/c-decl.c.jj 2013-09-18 12:06:04.084769192 +0200 +++ gcc/c/c-decl.c 2013-09-18 13:07:50.800968109 +0200 @@ -10228,4 +10228,106 @@ c_register_addr_space (const char *word, ridpointers [rid] = id; } +/* Return identifier to look up for omp declare reduction. */ + +tree +c_omp_reduction_id (enum tree_code reduction_code, tree reduction_id) +{ + const char *p = NULL; + switch (reduction_code) + { + case PLUS_EXPR: p = "+"; break; + case MULT_EXPR: p = "*"; break; + case MINUS_EXPR: p = "-"; break; + case BIT_AND_EXPR: p = "&"; break; + case BIT_XOR_EXPR: p = "^"; break; + case BIT_IOR_EXPR: p = "|"; break; + case TRUTH_ANDIF_EXPR: p = "&&"; break; + case TRUTH_ORIF_EXPR: p = "||"; break; + case MIN_EXPR: p = "min"; break; + case MAX_EXPR: p = "max"; break; + default: + break; + } + + if (p == NULL) + { + if (TREE_CODE (reduction_id) != IDENTIFIER_NODE) + return error_mark_node; + p = IDENTIFIER_POINTER (reduction_id); + } + + const char prefix[] = "omp declare reduction "; + size_t lenp = sizeof (prefix); + size_t len = strlen (p); + char *name = XALLOCAVEC (char, lenp + len); + memcpy (name, prefix, lenp - 1); + memcpy (name + lenp - 1, p, len + 1); + return get_identifier (name); +} + +/* Lookup REDUCTION_ID in the current scope, or create an artificial + VAR_DECL, bind it into the current scope and return it. */ + +tree +c_omp_reduction_decl (tree reduction_id) +{ + struct c_binding *b = I_SYMBOL_BINDING (reduction_id); + if (b != NULL && B_IN_CURRENT_SCOPE (b)) + return b->decl; + + tree decl = build_decl (BUILTINS_LOCATION, VAR_DECL, + reduction_id, integer_type_node); + DECL_ARTIFICIAL (decl) = 1; + DECL_EXTERNAL (decl) = 1; + TREE_STATIC (decl) = 1; + TREE_PUBLIC (decl) = 0; + bind (reduction_id, decl, current_scope, true, false, BUILTINS_LOCATION); + return decl; +} + +/* Lookup REDUCTION_ID in the first scope where it has entry for TYPE. */ + +tree +c_omp_reduction_lookup (tree reduction_id, tree type) +{ + struct c_binding *b = I_SYMBOL_BINDING (reduction_id); + while (b) + { + tree t; + for (t = DECL_INITIAL (b->decl); t; t = TREE_CHAIN (t)) + if (comptypes (TREE_PURPOSE (t), type)) + return TREE_VALUE (t); + b = b->shadowed; + } + return error_mark_node; +} + +/* Helper function called via walk_tree, to diagnose invalid + #pragma omp declare reduction combiners or initializers. */ + +tree +c_check_omp_declare_reduction_r (tree *tp, int *, void *data) +{ + tree *vars = (tree *) data; + if (SSA_VAR_P (*tp) + && !DECL_ARTIFICIAL (*tp) + && *tp != vars[0] + && *tp != vars[1]) + { + location_t loc = DECL_SOURCE_LOCATION (vars[0]); + if (strcmp (IDENTIFIER_POINTER (DECL_NAME (vars[0])), "omp_out") == 0) + error_at (loc, "%<#pragma omp declare reduction%> combiner refers to " + "variable %qD which is not % nor %", + *tp); + else + error_at (loc, "%<#pragma omp declare reduction%> initializer refers " + "to variable %qD which is not % nor " + "%", + *tp); + return *tp; + } + return NULL_TREE; +} + #include "gt-c-c-decl.h" --- gcc/testsuite/gcc.dg/gomp/udr-3.c.jj 2013-09-18 13:07:50.800968109 +0200 +++ gcc/testsuite/gcc.dg/gomp/udr-3.c 2013-09-18 13:07:50.800968109 +0200 @@ -0,0 +1,77 @@ +/* { dg-do compile } */ +/* { dg-options "-fopenmp" } */ + +struct S { int s; }; +struct T { int t; }; +struct U { int u; }; + +#pragma omp declare reduction (+: struct S: omp_out.s += omp_in.s) +#pragma omp declare reduction (*: struct S: omp_out.s *= omp_in.s) \ + initializer (omp_priv = {1}) +#pragma omp declare reduction (foo: struct S: omp_out.s += omp_in.s) + +void +f1 () +{ + struct S s, s2; + struct T t; + #pragma omp declare reduction (+: struct T: omp_out.t += omp_in.t) + #pragma omp parallel reduction (+: t) reduction (foo: s) reduction (*: s2) + s.s = 1, t.t = 1, s2.s = 2; + #pragma omp parallel reduction (+: s) + s.s = 1; +} + +void bar (struct S *); + +void +f2 () +{ + #pragma omp declare reduction (foo: struct S: omp_out.s += omp_in.s) initializer (bar (&omp_priv)) + #pragma omp declare reduction (bar: struct S: omp_out.s += omp_in.s) initializer (bar (&omp_orig)) /* { dg-error "one of the initializer call arguments should be" } */ +} + +#pragma omp declare reduction (+: struct U: omp_out.u *= omp_in.u) /* { dg-error "previous" } */ +#pragma omp declare reduction (+: struct U: omp_out.u += omp_in.u) /* { dg-error "redeclaration of" } */ + +void +f3 () +{ + #pragma omp declare reduction (f3: struct U: omp_out.u *= omp_in.u) /* { dg-error "previous" } */ + #pragma omp declare reduction (f3: struct U: omp_out.u += omp_in.u) /* { dg-error "redeclaration of" } */ +} + +struct V +{ + #pragma omp declare reduction (bar: struct S: omp_out.s *= omp_in.s) /* { dg-error "not at file or block scope" } */ + #pragma omp declare reduction (bar: struct S: omp_out.s += omp_in.s) /* { dg-error "not at file or block scope" } */ +}; + +#pragma omp declare reduction (n3: long: omp_out += omp_in) /* { dg-error "previous" } */ +#pragma omp declare reduction (n3: long int: omp_out += omp_in) /* { dg-error "redeclaration of" } */ +#pragma omp declare reduction (n3: short unsigned: omp_out += omp_in) +#pragma omp declare reduction (n3: short int: omp_out += omp_in) + +void +f4 (void) +{ + #pragma omp declare reduction (f4: long: omp_out += omp_in) /* { dg-error "previous" } */ + #pragma omp declare reduction (f4: long int: omp_out += omp_in) /* { dg-error "redeclaration of" } */ + #pragma omp declare reduction (f4: short unsigned: omp_out += omp_in) + #pragma omp declare reduction (f4: short int: omp_out += omp_in) +} + +void +f5 (void) +{ + #pragma omp declare reduction (+: struct S: omp_out.s += omp_in.s) initializer (omp_priv) /* { dg-error "expected" } */ + #pragma omp declare reduction (+: struct T: omp_out.t += omp_in.t) initializer (omp_priv ()) /* { dg-error "expected" } */ +} + +void +f6 (a, b) +#pragma omp declare reduction (bar: struct S: omp_out.s *= omp_in.s) /* { dg-error "expected declaration specifiers before" } */ + int a; + int b; +{ +} --- gcc/testsuite/gcc.dg/gomp/udr-1.c.jj 2013-09-18 13:07:50.801967987 +0200 +++ gcc/testsuite/gcc.dg/gomp/udr-1.c 2013-09-18 13:07:50.801967987 +0200 @@ -0,0 +1,46 @@ +/* { dg-do compile } */ +/* { dg-options "-fopenmp" } */ + +#pragma omp declare reduction (| : long int : omp_out |= omp_in) /* { dg-error "predeclared arithmetic type" } */ +#pragma omp declare reduction (+ : char : omp_out += omp_in) /* { dg-error "predeclared arithmetic type" } */ +typedef short T; +#pragma omp declare reduction (min : T : omp_out += omp_in) /* { dg-error "predeclared arithmetic type" } */ +#pragma omp declare reduction (* : _Complex double : omp_out *= omp_in) /* { dg-error "predeclared arithmetic type" } */ + +void +foo (void) +{ + #pragma omp declare reduction (| : long int : omp_out |= omp_in) /* { dg-error "predeclared arithmetic type" } */ + #pragma omp declare reduction (+ : char : omp_out += omp_in) /* { dg-error "predeclared arithmetic type" } */ + #pragma omp declare reduction (min : T : omp_out += omp_in) /* { dg-error "predeclared arithmetic type" } */ + #pragma omp declare reduction (* : _Complex double : omp_out *= omp_in) /* { dg-error "predeclared arithmetic type" } */ +} + +#pragma omp declare reduction (| : __typeof (foo) : omp_out |= omp_in) /* { dg-error "function or array" } */ +#pragma omp declare reduction (+ : char () : omp_out += omp_in) /* { dg-error "function or array" } */ +#pragma omp declare reduction (min : T[2] : omp_out += omp_in) /* { dg-error "function or array" } */ + +void +bar (void) +{ + #pragma omp declare reduction (| : __typeof (foo) : omp_out |= omp_in)/* { dg-error "function or array" } */ + #pragma omp declare reduction (+ : char () : omp_out += omp_in) /* { dg-error "function or array" } */ + #pragma omp declare reduction (min : T[2] : omp_out += omp_in) /* { dg-error "function or array" } */ +} + +struct A { int a; }; +#pragma omp declare reduction (| : const struct A : omp_out.a |= omp_in.a) /* { dg-error "const, volatile or restrict" } */ +#pragma omp declare reduction (+ : __const struct A : omp_out.a += omp_in.a) /* { dg-error "const, volatile or restrict" } */ +typedef volatile struct A T2; +#pragma omp declare reduction (min : T2 : omp_out.a += omp_in.a) /* { dg-error "const, volatile or restrict" } */ +#pragma omp declare reduction (* : struct A *__restrict : omp_out->a *= omp_in->a)/* { dg-error "const, volatile or restrict" } */ + +void +baz (void) +{ + #pragma omp declare reduction (| : const struct A : omp_out.a |= omp_in.a) /* { dg-error "const, volatile or restrict" } */ + #pragma omp declare reduction (+ : __const struct A : omp_out.a += omp_in.a) /* { dg-error "const, volatile or restrict" } */ + typedef volatile struct A T3; + #pragma omp declare reduction (min : T3 : omp_out.a += omp_in.a) /* { dg-error "const, volatile or restrict" } */ + #pragma omp declare reduction (* : struct A *__restrict : omp_out->a *= omp_in->a)/* { dg-error "const, volatile or restrict" } */ +} --- gcc/testsuite/gcc.dg/gomp/clause-1.c.jj 2013-09-18 12:06:03.484772540 +0200 +++ gcc/testsuite/gcc.dg/gomp/clause-1.c 2013-09-18 13:07:50.801967987 +0200 @@ -11,7 +11,7 @@ int t; void foo (int x) { - char *p; + char *pp; struct S { int i; int j; } s; char a[32]; double d; @@ -42,11 +42,11 @@ foo (int x) ; #pragma omp p firstprivate (bar) /* { dg-error "is not a variable" } */ ; -#pragma omp p reduction (+:p) /* { dg-error "has invalid type for" } */ +#pragma omp p reduction (+:pp) /* { dg-error "user defined reduction not found for" } */ ; -#pragma omp p reduction (*:s) /* { dg-error "has invalid type for" } */ +#pragma omp p reduction (*:s) /* { dg-error "user defined reduction not found for" } */ ; -#pragma omp p reduction (-:a) /* { dg-error "has invalid type for" } */ +#pragma omp p reduction (-:a) /* { dg-error "user defined reduction not found for" } */ ; d = 0; #pragma omp p reduction (*:d) --- gcc/testsuite/gcc.dg/gomp/udr-4.c.jj 2013-09-18 13:07:50.801967987 +0200 +++ gcc/testsuite/gcc.dg/gomp/udr-4.c 2013-09-18 13:07:50.801967987 +0200 @@ -0,0 +1,6 @@ +/* { dg-do compile } */ + +struct S; +#pragma omp declare reduction (+:struct S:omp_out.s += omp_in.s) /* { dg-error "invalid use of undefined type" } */ +struct S { int s; }; +#pragma omp declare reduction (*:struct S:omp_out.s *= omp_in.s) --- gcc/testsuite/gcc.dg/gomp/udr-2.c.jj 2013-09-18 13:07:50.801967987 +0200 +++ gcc/testsuite/gcc.dg/gomp/udr-2.c 2013-09-18 13:07:50.801967987 +0200 @@ -0,0 +1,42 @@ +/* { dg-do compile } */ +/* { dg-options "-fopenmp" } */ + +struct W { int w; }; +void init (struct W *, int, int *); +int v; +#pragma omp declare reduction (foo : long int : omp_out |= v) /* { dg-error "combiner refers to variable" } */ +#pragma omp declare reduction (foo : char : omp_out = v) /* { dg-error "combiner refers to variable" } */ +typedef short T; +#pragma omp declare reduction (foo : T : omp_out += v) /* { dg-error "combiner refers to variable" } */ +#pragma omp declare reduction (foo : int : v *= omp_in) /* { dg-error "combiner refers to variable" } */ +#pragma omp declare reduction (foo : struct W : omp_out.w *= omp_in.w + v) /* { dg-error "combiner refers to variable" } */ + +void +foo (int v) +{ + #pragma omp declare reduction (foo : long int : omp_out |= v) /* { dg-error "combiner refers to variable" } */ + #pragma omp declare reduction (foo : char : omp_out = v) /* { dg-error "combiner refers to variable" } */ + #pragma omp declare reduction (foo : T : omp_out += v) /* { dg-error "combiner refers to variable" } */ + #pragma omp declare reduction (foo : int : v *= omp_in) /* { dg-error "combiner refers to variable" } */ + #pragma omp declare reduction (foo : struct W : omp_out.w *= omp_in.w + v) /* { dg-error "combiner refers to variable" } */ +} + +#pragma omp declare reduction (bar : long int : omp_out |= omp_in) initializer (omp_priv = v) /* { dg-error "initializer refers to variable" } */ +#pragma omp declare reduction (bar : char : omp_out += omp_in) initializer (omp_priv = ((char) v)) /* { dg-error "initializer refers to variable" } */ +#pragma omp declare reduction (bar : T : omp_out += omp_in) initializer (omp_priv = (short) v) /* { dg-error "initializer refers to variable" } */ +#pragma omp declare reduction (bar : _Complex double : omp_out *= omp_in) initializer (omp_priv = (v)) /* { dg-error "initializer refers to variable" } */ +#pragma omp declare reduction (bar : struct W : omp_out.w *= omp_in.w) initializer (omp_priv = { v } ) /* { dg-error "initializer refers to variable" } */ +#pragma omp declare reduction (bar2 : struct W : omp_out.w *= omp_in.w) initializer (init (&omp_priv, v, (int *) 0)) /* { dg-error "initializer refers to variable" } */ +#pragma omp declare reduction (bar3 : struct W : omp_out.w *= omp_in.w) initializer (init (&omp_priv, 0, &v)) /* { dg-error "initializer refers to variable" } */ + +void +bar (int v) +{ + #pragma omp declare reduction (bar : long int : omp_out |= omp_in) initializer (omp_priv = v) /* { dg-error "initializer refers to variable" } */ + #pragma omp declare reduction (bar : char : omp_out += omp_in) initializer (omp_priv = ((char) v)) /* { dg-error "initializer refers to variable" } */ + #pragma omp declare reduction (bar : T : omp_out += omp_in) initializer (omp_priv = (short) v) /* { dg-error "initializer refers to variable" } */ + #pragma omp declare reduction (bar : _Complex double : omp_out *= omp_in) initializer (omp_priv = (v)) /* { dg-error "initializer refers to variable" } */ + #pragma omp declare reduction (bar : struct W : omp_out.w *= omp_in.w) initializer (omp_priv = { v }) /* { dg-error "initializer refers to variable" } */ + #pragma omp declare reduction (bar2 : struct W : omp_out.w *= omp_in.w) initializer (init (&omp_priv, v, (int *) 0)) /* { dg-error "initializer refers to variable" } */ + #pragma omp declare reduction (bar3 : struct W : omp_out.w *= omp_in.w) initializer (init (&omp_priv, 0, &v)) /* { dg-error "initializer refers to variable" } */ +} --- libgomp/testsuite/libgomp.c++/udr-9.C.jj 2013-09-18 13:07:50.802967867 +0200 +++ libgomp/testsuite/libgomp.c++/udr-9.C 2013-09-18 13:07:50.802967867 +0200 @@ -0,0 +1,3 @@ +// { dg-do run } + +#include "../libgomp.c/udr-1.c" --- libgomp/testsuite/libgomp.c/udr-3.c.jj 2013-09-18 13:07:50.802967867 +0200 +++ libgomp/testsuite/libgomp.c/udr-3.c 2013-09-18 13:07:50.802967867 +0200 @@ -0,0 +1,32 @@ +/* { dg-do run } */ + +extern void abort (); + +struct S; +void foo (struct S *, struct S *); +#pragma omp declare reduction (+:struct S:foo (&omp_out, &omp_in)) +struct S { int s; }; + +void +foo (struct S *x, struct S *y) +{ + x->s += y->s; +} + +int +main () +{ + struct S s; + int i; + s.s = 0; + #pragma omp parallel reduction (+:s, i) + { + if (s.s != 0) + abort (); + s.s = 2; + i = 1; + } + if (s.s != 2 * i) + abort (); + return 0; +} --- libgomp/testsuite/libgomp.c/simd-4.c.jj 2013-09-18 13:11:46.235706835 +0200 +++ libgomp/testsuite/libgomp.c/simd-4.c 2013-09-18 13:13:12.474247404 +0200 @@ -0,0 +1,42 @@ +/* { 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 }; +struct S { int s; }; +#pragma omp declare reduction (+:struct S:omp_out.s += omp_in.s) +#pragma omp declare reduction (foo:struct S:omp_out.s += omp_in.s) +#pragma omp declare reduction (foo:int:omp_out += omp_in) + +__attribute__((noinline, noclone)) int +foo (void) +{ + int i, u = 0; + struct S s, t; + s.s = 0; t.s = 0; + #pragma omp simd aligned(a : 32) reduction(+:s) reduction(foo:t, u) + for (i = 0; i < 1024; i++) + { + int x = a[i]; + s.s += x; + t.s += x; + u += x; + } + if (t.s != s.s || u != s.s) + abort (); + return s.s; +} + +int +main () +{ + int i; + for (i = 0; i < 1024; i++) + a[i] = (i & 31) + (i / 128); + int s = foo (); + if (s != 19456) + abort (); + return 0; +} --- libgomp/testsuite/libgomp.c/udr-1.c.jj 2013-09-18 13:07:50.802967867 +0200 +++ libgomp/testsuite/libgomp.c/udr-1.c 2013-09-18 13:07:50.802967867 +0200 @@ -0,0 +1,81 @@ +/* { dg-do run } */ + +extern +#ifdef __cplusplus +"C" +#endif +void abort (); + +struct S { int s; struct S *t; }; + +void +foo (struct S *out, struct S *in) +{ + out->s += in->s; +} + +void +bar (struct S *x) +{ + if (x->s != 6) abort (); + x->s = 15; +} + +void +baz (struct S *x, struct S *y) +{ + x->s = 6; + x->t = x; + (void) y; +} + +#pragma omp declare reduction (foo: struct S: foo (&omp_out, &omp_in)) \ + initializer (omp_priv = { 8, &omp_priv }) +#pragma omp declare reduction (foo: char, int, short: omp_out += omp_in - 4) \ + initializer (omp_priv = 4) +#pragma omp declare reduction (+: struct S: foo (&omp_out, &omp_in)) \ + initializer (baz (&omp_priv, &omp_orig)) + +void +test (struct S s, struct S t) +{ + int q = 0; + #pragma omp parallel num_threads (4) reduction (+: s, q) reduction (foo: t) + { + if (s.s != 6 || s.t != &s || t.s != 8 || t.t != &t) + abort (); + s.s = 2; + t.s = 3; + q = 1; + } + if (s.s != 12 + 2 * q || t.s != 14 + 3 * q) + abort (); +} + +int +main () +{ + struct S s, t; + s.s = 9; t.s = 10; + int h = 30, v = 2, q = 0; + #pragma omp declare reduction (foo: struct S: omp_out.s *= omp_in.s) \ + initializer (omp_priv = omp_orig) + { + #pragma omp declare reduction (foo: struct S: omp_out.s += omp_in.s) \ + initializer (omp_priv = omp_orig) + #pragma omp parallel num_threads (4) reduction (+: t, q) \ + reduction (min: h) reduction (foo: s, v) + { + if (s.s != 9 || t.s != 6 || v != 4 || h != __INT_MAX__) abort (); + asm volatile ("" : "+m" (s.s), "+m" (t.s)); + asm volatile ("" : "+r" (h), "+r" (v)); + h = t.s; s.s++; t.s++; v++; q++; + } + } + if (h != 6 || s.s != 9 + q * 10 || t.s != 10 + q * 7 || v != 2 + q) + abort (); + s.s = 12; + t.s = 14; + test (s, t); + return 0; +} --- libgomp/testsuite/libgomp.c/udr-2.c.jj 2013-09-18 13:07:50.802967867 +0200 +++ libgomp/testsuite/libgomp.c/udr-2.c 2013-09-18 13:07:50.802967867 +0200 @@ -0,0 +1,27 @@ +/* { dg-do run } */ + +extern void abort (); + +struct S { int s; }; + +#pragma omp declare reduction (+:struct S:omp_out.s += omp_in.s) +#pragma omp declare reduction (foo:struct S:omp_out.s += omp_in.s) +#pragma omp declare reduction (foo:int:omp_out += omp_in) + +int +main () +{ + int i, u = 0, q = 0; + struct S s, t; + s.s = 0; t.s = 0; + #pragma omp parallel reduction(+:s, q) reduction(foo:t, u) + { + if (s.s != 0 || t.s != 0 || u != 0 || q != 0) abort (); + s.s = 6; + t.s = 8; + u = 9; + q++; + } + if (s.s != 6 * q || t.s != 8 * q || u != 9 * q) abort (); + return 0; +} --- libgomp/testsuite/libgomp.c/simd-5.c.jj 2013-09-18 13:11:49.253690612 +0200 +++ libgomp/testsuite/libgomp.c/simd-5.c 2013-09-18 13:13:54.117026283 +0200 @@ -0,0 +1,44 @@ +/* { 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 }; +struct S { int s; }; +#pragma omp declare reduction (+:struct S:omp_out.s += omp_in.s) +#pragma omp declare reduction (foo:struct S:omp_out.s += omp_in.s) +#pragma omp declare reduction (foo:int:omp_out += omp_in) + +__attribute__((noinline, noclone)) int +foo (void) +{ + int i, u = 0, q = 0; + struct S s, t; + s.s = 0; t.s = 0; + #pragma omp simd aligned(a : 32) reduction(+:s, q) reduction(foo:t, u) \ + safelen(1) + for (i = 0; i < 1024; i++) + { + int x = a[i]; + s.s += x; + t.s += x; + u += x; + q++; + } + if (t.s != s.s || u != s.s || q != 1024) + abort (); + return s.s; +} + +int +main () +{ + int i; + for (i = 0; i < 1024; i++) + a[i] = (i & 31) + (i / 128); + int s = foo (); + if (s != 19456) + abort (); + return 0; +}