This is the mail archive of the
gcc-patches@gcc.gnu.org
mailing list for the GCC project.
[gomp4] C UDR support
- From: Jakub Jelinek <jakub at redhat dot com>
- To: "Joseph S. Myers" <joseph at codesourcery dot com>
- Cc: gcc-patches at gcc dot gnu dot org
- Date: Wed, 18 Sep 2013 13:38:27 +0200
- Subject: [gomp4] C UDR support
- Authentication-results: sourceware.org; auth=none
- Reply-to: Jakub Jelinek <jakub at redhat dot com>
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 <jakub@redhat.com>
* 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.
--- 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 %<reduction%>", 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<tree> types = vNULL;
+ vec<c_token> 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 %<+%>, %<*%>, %<-%>, %<&%>, "
+ "%<^%>, %<|%>, %<&&%>, %<||%>, %<min%> 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 %<omp_priv%> 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 %<omp_out%> nor %<omp_in%>",
+ *tp);
+ else
+ error_at (loc, "%<#pragma omp declare reduction%> initializer refers "
+ "to variable %qD which is not %<omp_priv%> nor "
+ "%<omp_orig%>",
+ *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;
+}
Jakub