+2011-08-02 Jakub Jelinek <jakub@redhat.com>
+
+ * c-parser.c (enum c_parser_prec): New enum, moved from within
+ c_parser_binary_expression.
+ (c_parser_binary_expression): Add PREC argument. Stop parsing
+ if operator has lower or equal precedence than PREC.
+ (c_parser_conditional_expression, c_parser_omp_for_loop): Adjust
+ callers.
+ (c_parser_omp_atomic): Handle parsing OpenMP 3.1 atomics.
+ Adjust c_finish_omp_atomic caller.
+ (c_parser_omp_taskyield): New function.
+ (c_parser_pragma): Handle PRAGMA_OMP_TASKYIELD.
+ (c_parser_omp_clause_name): Handle final and mergeable clauses.
+ (c_parser_omp_clause_final, c_parser_omp_clause_mergeable): New
+ functions.
+ (c_parser_omp_all_clauses): Handle PRAGMA_OMP_CLAUSE_FINAL
+ and PRAGMA_OMP_CLAUSE_MERGEABLE.
+ (OMP_TASK_CLAUSE_MASK): Allow final and mergeable clauses.
+ (c_parser_omp_clause_reduction): Handle min and max.
+ * c-typeck.c (c_finish_omp_clauses): Don't complain about
+ const qualified predetermined vars in firstprivate clause.
+ andle OMP_CLAUSE_FINAL and OMP_CLAUSE_MERGEABLE.
+ Handle MIN_EXPR and MAX_EXPR.
+ * tree-pretty-print.c (dump_omp_clause): Handle OMP_CLAUSE_FINAL
+ and OMP_CLAUSE_MERGEABLE.
+ (dump_generic_node): Handle OMP_ATOMIC_READ, OMP_ATOMIC_CAPTURE_OLD
+ and OMP_ATOMIC_CAPTURE_NEW.
+ * tree.c (omp_clause_num_ops): Add OMP_CLAUSE_FINAL and
+ OMP_CLAUSE_MERGEABLE.
+ (omp_clause_code_name): Likewise.
+ (walk_tree_1): Handle OMP_CLAUSE_FINAL and OMP_CLAUSE_MERGEABLE.
+ * tree.h (enum omp_clause_code): Add OMP_CLAUSE_FINAL
+ and OMP_CLAUSE_MERGEABLE.
+ (OMP_CLAUSE_FINAL_EXPR): Define.
+ * omp-low.c (scan_sharing_clauses): Handle OMP_CLAUSE_FINAL and
+ OMP_CLAUSE_MERGEABLE.
+ (expand_task_call): Likewise.
+ (expand_omp_atomic_load, expand_omp_atomic_store): New functions.
+ (expand_omp_atomic_fetch_op): Handle cases where old or new
+ value is needed afterwards.
+ (expand_omp_atomic): Call expand_omp_atomic_load resp.
+ expand_omp_atomic_store.
+ * gimplify.c (gimplify_omp_atomic, gimplify_expr): Handle
+ OMP_ATOMIC_READ, OMP_ATOMIC_CAPTURE_OLD and OMP_ATOMIC_CAPTURE_NEW.
+ (gimplify_scan_omp_clauses, gimplify_adjust_omp_clauses): Handle
+ OMP_CLAUSE_FINAL and OMP_CLAUSE_MERGEABLE.
+ * tree-nested.c (convert_nonlocal_omp_clauses,
+ convert_local_omp_clauses): Likewise.
+ * tree.def (OMP_ATOMIC_READ, OMP_ATOMIC_CAPTURE_OLD,
+ OMP_ATOMIC_CAPTURE_NEW): New.
+ * gimple.h (GF_OMP_ATOMIC_NEED_VALUE): New.
+ (gimple_omp_atomic_need_value_p, gimple_omp_atomic_set_need_value):
+ New inlines.
+ * omp-builtins.def (BUILT_IN_GOMP_TASKYIELD): New builtin.
+ * doc/generic.texi: Mention OMP_CLAUSE_COLLAPSE,
+ OMP_CLAUSE_UNTIED, OMP_CLAUSE_FINAL and OMP_CLAUSE_MERGEABLE.
+
2011-08-02 Kai Tietz <ktietz@redhat.com>
* gimple.c (canonicalize_cond_expr_cond): Handle cast from
+2011-08-02 Jakub Jelinek <jakub@redhat.com>
+
+ * c-common.h (c_finish_omp_atomic): Adjust prototype.
+ (c_finish_omp_taskyield): New prototype.
+ * c-omp.c (c_finish_omp_atomic): Add OPCODE, V, LHS1 and RHS1
+ arguments. Handle OMP_ATOMIC_READ, OMP_ATOMIC_CAPTURE_OLD and
+ OMP_ATOMIC_CAPTURE_NEW in addition to OMP_ATOMIC. If LHS1
+ or RHS1 have side-effects, evaluate those too in the right spot,
+ if it is a decl and LHS is also a decl, error out if they
+ aren't the same.
+ (c_finish_omp_taskyield): New function.
+ * c-cppbuiltin.c (c_cpp_builtins): Change _OPENMP to 201107.
+ * c-pragma.c (omp_pragmas): Add taskyield.
+ * c-pragma.h (enum pragma_kind): Add PRAGMA_OMP_TASKYIELD.
+ (enum pragma_omp_clause): Add PRAGMA_OMP_CLAUSE_FINAL and
+ PRAGMA_OMP_CLAUSE_MERGEABLE.
+
2011-07-25 Dodji Seketeli <dodji@redhat.com>
* c-common.h (set_underlying_type): Remove parm name from
extern tree c_finish_omp_critical (location_t, tree, tree);
extern tree c_finish_omp_ordered (location_t, tree);
extern void c_finish_omp_barrier (location_t);
-extern tree c_finish_omp_atomic (location_t, enum tree_code, tree, tree);
+extern tree c_finish_omp_atomic (location_t, enum tree_code, enum tree_code,
+ tree, tree, tree, tree, tree);
extern void c_finish_omp_flush (location_t);
extern void c_finish_omp_taskwait (location_t);
+extern void c_finish_omp_taskyield (location_t);
extern tree c_finish_omp_for (location_t, tree, tree, tree, tree, tree, tree);
extern void c_split_parallel_clauses (location_t, tree, tree *, tree *);
extern enum omp_clause_default_kind c_omp_predetermined_sharing (tree);
cpp_define (pfile, "__SSP__=1");
if (flag_openmp)
- cpp_define (pfile, "_OPENMP=200805");
+ cpp_define (pfile, "_OPENMP=201107");
if (int128_integer_type_node != NULL_TREE)
builtin_define_type_sizeof ("__SIZEOF_INT128__",
/* This file contains routines to construct GNU OpenMP constructs,
called from parsing in the C and C++ front ends.
- Copyright (C) 2005, 2007, 2008, 2009, 2010 Free Software Foundation, Inc.
+ Copyright (C) 2005, 2007, 2008, 2009, 2010, 2011
+ Free Software Foundation, Inc.
Contributed by Richard Henderson <rth@redhat.com>,
Diego Novillo <dnovillo@redhat.com>.
}
-/* Complete a #pragma omp atomic construct. The expression to be
- implemented atomically is LHS code= RHS. LOC is the location of
- the atomic statement. The value returned is either error_mark_node
- (if the construct was erroneous) or an OMP_ATOMIC node which should
- be added to the current statement tree with add_stmt.*/
+/* Complete a #pragma omp taskyield construct. LOC is the location of the
+ pragma. */
+
+void
+c_finish_omp_taskyield (location_t loc)
+{
+ tree x;
+
+ x = built_in_decls[BUILT_IN_GOMP_TASKYIELD];
+ x = build_call_expr_loc (loc, x, 0);
+ add_stmt (x);
+}
+
+
+/* Complete a #pragma omp atomic construct. For CODE OMP_ATOMIC
+ the expression to be implemented atomically is LHS opcode= RHS.
+ For OMP_ATOMIC_READ V = LHS, for OMP_ATOMIC_CAPTURE_{NEW,OLD} LHS
+ opcode= RHS with the new or old content of LHS returned.
+ LOC is the location of the atomic statement. The value returned
+ is either error_mark_node (if the construct was erroneous) or an
+ OMP_ATOMIC* node which should be added to the current statement
+ tree with add_stmt. */
tree
-c_finish_omp_atomic (location_t loc, enum tree_code code, tree lhs, tree rhs)
+c_finish_omp_atomic (location_t loc, enum tree_code code,
+ enum tree_code opcode, tree lhs, tree rhs,
+ tree v, tree lhs1, tree rhs1)
{
tree x, type, addr;
- if (lhs == error_mark_node || rhs == error_mark_node)
+ if (lhs == error_mark_node || rhs == error_mark_node
+ || v == error_mark_node || lhs1 == error_mark_node
+ || rhs1 == error_mark_node)
return error_mark_node;
/* ??? According to one reading of the OpenMP spec, complex type are
}
lhs = build_indirect_ref (loc, addr, RO_NULL);
+ if (code == OMP_ATOMIC_READ)
+ {
+ x = build1 (OMP_ATOMIC_READ, type, addr);
+ SET_EXPR_LOCATION (x, loc);
+ return build_modify_expr (loc, v, NULL_TREE, NOP_EXPR,
+ loc, x, NULL_TREE);
+ return x;
+ }
+
/* There are lots of warnings, errors, and conversions that need to happen
in the course of interpreting a statement. Use the normal mechanisms
to do this, and then take it apart again. */
- x = build_modify_expr (input_location, lhs, NULL_TREE, code,
+ x = build_modify_expr (input_location, lhs, NULL_TREE, opcode,
input_location, rhs, NULL_TREE);
if (x == error_mark_node)
return error_mark_node;
rhs = TREE_OPERAND (x, 1);
/* Punt the actual generation of atomic operations to common code. */
- x = build2 (OMP_ATOMIC, void_type_node, addr, rhs);
+ if (code == OMP_ATOMIC)
+ type = void_type_node;
+ x = build2 (code, type, addr, rhs);
SET_EXPR_LOCATION (x, loc);
+
+ /* Generally it is hard to prove lhs1 and lhs are the same memory
+ location, just diagnose different variables. */
+ if (rhs1
+ && TREE_CODE (rhs1) == VAR_DECL
+ && TREE_CODE (lhs) == VAR_DECL
+ && rhs1 != lhs)
+ {
+ if (code == OMP_ATOMIC)
+ error_at (loc, "%<#pragma omp atomic update%> uses two different variables for memory");
+ else
+ error_at (loc, "%<#pragma omp atomic capture%> uses two different variables for memory");
+ return error_mark_node;
+ }
+
+ if (code != OMP_ATOMIC)
+ {
+ /* Generally it is hard to prove lhs1 and lhs are the same memory
+ location, just diagnose different variables. */
+ if (lhs1 && TREE_CODE (lhs1) == VAR_DECL && TREE_CODE (lhs) == VAR_DECL)
+ {
+ if (lhs1 != lhs)
+ {
+ error_at (loc, "%<#pragma omp atomic capture%> uses two different variables for memory");
+ return error_mark_node;
+ }
+ }
+ x = build_modify_expr (loc, v, NULL_TREE, NOP_EXPR,
+ loc, x, NULL_TREE);
+ if (rhs1 && rhs1 != lhs)
+ {
+ tree rhs1addr = build_unary_op (loc, ADDR_EXPR, rhs1, 0);
+ if (rhs1addr == error_mark_node)
+ return error_mark_node;
+ x = omit_one_operand_loc (loc, type, x, rhs1addr);
+ }
+ if (lhs1 && lhs1 != lhs)
+ {
+ tree lhs1addr = build_unary_op (loc, ADDR_EXPR, lhs1, 0);
+ if (lhs1addr == error_mark_node)
+ return error_mark_node;
+ if (code == OMP_ATOMIC_CAPTURE_OLD)
+ x = omit_one_operand_loc (loc, type, x, lhs1addr);
+ else
+ {
+ x = save_expr (x);
+ x = omit_two_operands_loc (loc, type, x, x, lhs1addr);
+ }
+ }
+ }
+ else if (rhs1 && rhs1 != lhs)
+ {
+ tree rhs1addr = build_unary_op (loc, ADDR_EXPR, rhs1, 0);
+ if (rhs1addr == error_mark_node)
+ return error_mark_node;
+ x = omit_one_operand_loc (loc, type, x, rhs1addr);
+ }
+
return x;
}
{ "single", PRAGMA_OMP_SINGLE },
{ "task", PRAGMA_OMP_TASK },
{ "taskwait", PRAGMA_OMP_TASKWAIT },
+ { "taskyield", PRAGMA_OMP_TASKYIELD },
{ "threadprivate", PRAGMA_OMP_THREADPRIVATE }
};
PRAGMA_OMP_SINGLE,
PRAGMA_OMP_TASK,
PRAGMA_OMP_TASKWAIT,
+ PRAGMA_OMP_TASKYIELD,
PRAGMA_OMP_THREADPRIVATE,
PRAGMA_GCC_PCH_PREPROCESS,
PRAGMA_OMP_CLAUSE_REDUCTION,
PRAGMA_OMP_CLAUSE_SCHEDULE,
PRAGMA_OMP_CLAUSE_SHARED,
- PRAGMA_OMP_CLAUSE_UNTIED
+ PRAGMA_OMP_CLAUSE_UNTIED,
+ PRAGMA_OMP_CLAUSE_FINAL,
+ PRAGMA_OMP_CLAUSE_MERGEABLE
} pragma_omp_clause;
extern struct cpp_reader* parse_in;
C_DTR_PARM
} c_dtr_syn;
+/* The binary operation precedence levels, where 0 is a dummy lowest level
+ used for the bottom of the stack. */
+enum c_parser_prec {
+ PREC_NONE,
+ PREC_LOGOR,
+ PREC_LOGAND,
+ PREC_BITOR,
+ PREC_BITXOR,
+ PREC_BITAND,
+ PREC_EQ,
+ PREC_REL,
+ PREC_SHIFT,
+ PREC_ADD,
+ PREC_MULT,
+ NUM_PRECS
+};
+
static void c_parser_external_declaration (c_parser *);
static void c_parser_asm_definition (c_parser *);
static void c_parser_declaration_or_fndef (c_parser *, bool, bool, bool,
static struct c_expr c_parser_expr_no_commas (c_parser *, struct c_expr *);
static struct c_expr c_parser_conditional_expression (c_parser *,
struct c_expr *);
-static struct c_expr c_parser_binary_expression (c_parser *, struct c_expr *);
+static struct c_expr c_parser_binary_expression (c_parser *, struct c_expr *,
+ enum c_parser_prec);
static struct c_expr c_parser_cast_expression (c_parser *, struct c_expr *);
static struct c_expr c_parser_unary_expression (c_parser *);
static struct c_expr c_parser_sizeof_expression (c_parser *);
static void c_parser_omp_barrier (c_parser *);
static void c_parser_omp_flush (c_parser *);
static void c_parser_omp_taskwait (c_parser *);
+static void c_parser_omp_taskyield (c_parser *);
enum pragma_context { pragma_external, pragma_stmt, pragma_compound };
static bool c_parser_pragma (c_parser *, enum pragma_context);
gcc_assert (!after || c_dialect_objc ());
- cond = c_parser_binary_expression (parser, after);
+ cond = c_parser_binary_expression (parser, after, PREC_NONE);
if (c_parser_next_token_is_not (parser, CPP_QUERY))
return cond;
/* Parse a binary expression; that is, a logical-OR-expression (C90
6.3.5-6.3.14, C99 6.5.5-6.5.14). If AFTER is not NULL then it is
an Objective-C message expression which is the primary-expression
- starting the expression as an initializer.
+ starting the expression as an initializer. PREC is the starting
+ precedence, usually PREC_NONE.
multiplicative-expression:
cast-expression
*/
static struct c_expr
-c_parser_binary_expression (c_parser *parser, struct c_expr *after)
+c_parser_binary_expression (c_parser *parser, struct c_expr *after,
+ enum c_parser_prec prec)
{
/* A binary expression is parsed using operator-precedence parsing,
with the operands being cast expressions. All the binary
expressions, we also need to adjust c_inhibit_evaluation_warnings
as appropriate when the operators are pushed and popped. */
- /* The precedence levels, where 0 is a dummy lowest level used for
- the bottom of the stack. */
- enum prec {
- PREC_NONE,
- PREC_LOGOR,
- PREC_LOGAND,
- PREC_BITOR,
- PREC_BITXOR,
- PREC_BITAND,
- PREC_EQ,
- PREC_REL,
- PREC_SHIFT,
- PREC_ADD,
- PREC_MULT,
- NUM_PRECS
- };
struct {
/* The expression at this stack level. */
struct c_expr expr;
/* The precedence of the operator on its left, PREC_NONE at the
bottom of the stack. */
- enum prec prec;
+ enum c_parser_prec prec;
/* The operation on its left. */
enum tree_code op;
/* The source location of this operation. */
gcc_assert (!after || c_dialect_objc ());
stack[0].loc = c_parser_peek_token (parser)->location;
stack[0].expr = c_parser_cast_expression (parser, after);
- stack[0].prec = PREC_NONE;
+ stack[0].prec = prec;
sp = 0;
while (true)
{
- enum prec oprec;
+ enum c_parser_prec oprec;
enum tree_code ocode;
if (parser->error)
goto out;
goto out;
}
binary_loc = c_parser_peek_token (parser)->location;
- c_parser_consume_token (parser);
while (oprec <= stack[sp].prec)
- POP;
+ {
+ if (sp == 0)
+ goto out;
+ POP;
+ }
+ c_parser_consume_token (parser);
switch (ocode)
{
case TRUTH_ANDIF_EXPR:
c_parser_omp_taskwait (parser);
return false;
+ case PRAGMA_OMP_TASKYIELD:
+ if (context != pragma_compound)
+ {
+ if (context == pragma_stmt)
+ c_parser_error (parser, "%<#pragma omp taskyield%> may only be "
+ "used in compound statements");
+ goto bad_stmt;
+ }
+ c_parser_omp_taskyield (parser);
+ return false;
+
case PRAGMA_OMP_THREADPRIVATE:
c_parser_omp_threadprivate (parser);
return false;
result = PRAGMA_OMP_CLAUSE_COPYPRIVATE;
break;
case 'f':
- if (!strcmp ("firstprivate", p))
+ if (!strcmp ("final", p))
+ result = PRAGMA_OMP_CLAUSE_FINAL;
+ else if (!strcmp ("firstprivate", p))
result = PRAGMA_OMP_CLAUSE_FIRSTPRIVATE;
break;
case 'l':
if (!strcmp ("lastprivate", p))
result = PRAGMA_OMP_CLAUSE_LASTPRIVATE;
break;
+ case 'm':
+ if (!strcmp ("mergeable", p))
+ result = PRAGMA_OMP_CLAUSE_MERGEABLE;
+ break;
case 'n':
if (!strcmp ("nowait", p))
result = PRAGMA_OMP_CLAUSE_NOWAIT;
return c_parser_omp_var_list_parens (parser, OMP_CLAUSE_FIRSTPRIVATE, list);
}
+/* OpenMP 3.1:
+ final ( expression ) */
+
+static tree
+c_parser_omp_clause_final (c_parser *parser, tree list)
+{
+ location_t loc = c_parser_peek_token (parser)->location;
+ if (c_parser_next_token_is (parser, CPP_OPEN_PAREN))
+ {
+ tree t = c_parser_paren_condition (parser);
+ tree c;
+
+ check_no_duplicate_clause (list, OMP_CLAUSE_FINAL, "final");
+
+ c = build_omp_clause (loc, OMP_CLAUSE_FINAL);
+ OMP_CLAUSE_FINAL_EXPR (c) = t;
+ OMP_CLAUSE_CHAIN (c) = list;
+ list = c;
+ }
+ else
+ c_parser_error (parser, "expected %<(%>");
+
+ return list;
+}
+
/* OpenMP 2.5:
if ( expression ) */
return c_parser_omp_var_list_parens (parser, OMP_CLAUSE_LASTPRIVATE, list);
}
+/* OpenMP 3.1:
+ mergeable */
+
+static tree
+c_parser_omp_clause_mergeable (c_parser *parser ATTRIBUTE_UNUSED, tree list)
+{
+ tree c;
+
+ /* FIXME: Should we allow duplicates? */
+ check_no_duplicate_clause (list, OMP_CLAUSE_MERGEABLE, "mergeable");
+
+ c = build_omp_clause (c_parser_peek_token (parser)->location,
+ OMP_CLAUSE_MERGEABLE);
+ OMP_CLAUSE_CHAIN (c) = list;
+
+ return c;
+}
+
/* OpenMP 2.5:
nowait */
reduction ( reduction-operator : variable-list )
reduction-operator:
- One of: + * - & ^ | && || */
+ One of: + * - & ^ | && ||
+
+ OpenMP 3.1:
+
+ reduction-operator:
+ One of: + * - & ^ | && || max min */
static tree
c_parser_omp_clause_reduction (c_parser *parser, tree list)
case CPP_OR_OR:
code = TRUTH_ORIF_EXPR;
break;
+ case CPP_NAME:
+ {
+ const char *p
+ = IDENTIFIER_POINTER (c_parser_peek_token (parser)->value);
+ if (strcmp (p, "min") == 0)
+ {
+ code = MIN_EXPR;
+ break;
+ }
+ if (strcmp (p, "max") == 0)
+ {
+ code = MAX_EXPR;
+ break;
+ }
+ }
+ /* FALLTHRU */
default:
c_parser_error (parser,
"expected %<+%>, %<*%>, %<-%>, %<&%>, "
- "%<^%>, %<|%>, %<&&%>, or %<||%>");
+ "%<^%>, %<|%>, %<&&%>, %<||%>, %<min%> or %<max%>");
c_parser_skip_until_found (parser, CPP_CLOSE_PAREN, 0);
return list;
}
clauses = c_parser_omp_clause_firstprivate (parser, clauses);
c_name = "firstprivate";
break;
+ case PRAGMA_OMP_CLAUSE_FINAL:
+ clauses = c_parser_omp_clause_final (parser, clauses);
+ c_name = "final";
+ break;
case PRAGMA_OMP_CLAUSE_IF:
clauses = c_parser_omp_clause_if (parser, clauses);
c_name = "if";
clauses = c_parser_omp_clause_lastprivate (parser, clauses);
c_name = "lastprivate";
break;
+ case PRAGMA_OMP_CLAUSE_MERGEABLE:
+ clauses = c_parser_omp_clause_mergeable (parser, clauses);
+ c_name = "mergeable";
+ break;
case PRAGMA_OMP_CLAUSE_NOWAIT:
clauses = c_parser_omp_clause_nowait (parser, clauses);
c_name = "nowait";
where x is an lvalue expression with scalar type.
+ OpenMP 3.1:
+ # pragma omp atomic new-line
+ update-stmt
+
+ # pragma omp atomic read new-line
+ read-stmt
+
+ # pragma omp atomic write new-line
+ write-stmt
+
+ # pragma omp atomic update new-line
+ update-stmt
+
+ # pragma omp atomic capture new-line
+ capture-stmt
+
+ # pragma omp atomic capture new-line
+ capture-block
+
+ read-stmt:
+ v = x
+ write-stmt:
+ x = expr
+ update-stmt:
+ expression-stmt | x = x binop expr
+ capture-stmt:
+ v = x binop= expr | v = x++ | v = ++x | v = x-- | v = --x
+ capture-block:
+ { v = x; update-stmt; } | { update-stmt; v = x; }
+
+ where x and v are lvalue expressions with scalar type.
+
LOC is the location of the #pragma token. */
static void
c_parser_omp_atomic (location_t loc, c_parser *parser)
{
- tree lhs, rhs;
- tree stmt;
- enum tree_code code;
+ tree lhs = NULL_TREE, rhs = NULL_TREE, v = NULL_TREE;
+ tree lhs1 = NULL_TREE, rhs1 = NULL_TREE;
+ tree stmt, orig_lhs;
+ enum tree_code code = OMP_ATOMIC, opcode = NOP_EXPR;
struct c_expr rhs_expr;
+ bool structured_block = false;
+ if (c_parser_next_token_is (parser, CPP_NAME))
+ {
+ const char *p = IDENTIFIER_POINTER (c_parser_peek_token (parser)->value);
+
+ if (!strcmp (p, "read"))
+ code = OMP_ATOMIC_READ;
+ else if (!strcmp (p, "write"))
+ code = NOP_EXPR;
+ else if (!strcmp (p, "update"))
+ code = OMP_ATOMIC;
+ else if (!strcmp (p, "capture"))
+ code = OMP_ATOMIC_CAPTURE_NEW;
+ else
+ p = NULL;
+ if (p)
+ c_parser_consume_token (parser);
+ }
c_parser_skip_to_pragma_eol (parser);
+ switch (code)
+ {
+ case OMP_ATOMIC_READ:
+ case NOP_EXPR: /* atomic write */
+ v = c_parser_unary_expression (parser).value;
+ v = c_fully_fold (v, false, NULL);
+ if (v == error_mark_node)
+ goto saw_error;
+ loc = c_parser_peek_token (parser)->location;
+ if (!c_parser_require (parser, CPP_EQ, "expected %<=%>"))
+ goto saw_error;
+ if (code == NOP_EXPR)
+ lhs = c_parser_expression (parser).value;
+ else
+ lhs = c_parser_unary_expression (parser).value;
+ lhs = c_fully_fold (lhs, false, NULL);
+ if (lhs == error_mark_node)
+ goto saw_error;
+ if (code == NOP_EXPR)
+ {
+ /* atomic write is represented by OMP_ATOMIC with NOP_EXPR
+ opcode. */
+ code = OMP_ATOMIC;
+ rhs = lhs;
+ lhs = v;
+ v = NULL_TREE;
+ }
+ goto done;
+ case OMP_ATOMIC_CAPTURE_NEW:
+ if (c_parser_next_token_is (parser, CPP_OPEN_BRACE))
+ {
+ c_parser_consume_token (parser);
+ structured_block = true;
+ }
+ else
+ {
+ v = c_parser_unary_expression (parser).value;
+ v = c_fully_fold (v, false, NULL);
+ if (v == error_mark_node)
+ goto saw_error;
+ if (!c_parser_require (parser, CPP_EQ, "expected %<=%>"))
+ goto saw_error;
+ }
+ break;
+ default:
+ break;
+ }
+
+ /* For structured_block case we don't know yet whether
+ old or new x should be captured. */
+restart:
lhs = c_parser_unary_expression (parser).value;
lhs = c_fully_fold (lhs, false, NULL);
+ orig_lhs = lhs;
switch (TREE_CODE (lhs))
{
case ERROR_MARK:
saw_error:
c_parser_skip_to_end_of_block_or_statement (parser);
+ if (structured_block)
+ {
+ if (c_parser_next_token_is (parser, CPP_CLOSE_BRACE))
+ c_parser_consume_token (parser);
+ else if (code == OMP_ATOMIC_CAPTURE_NEW)
+ {
+ c_parser_skip_to_end_of_block_or_statement (parser);
+ if (c_parser_next_token_is (parser, CPP_CLOSE_BRACE))
+ c_parser_consume_token (parser);
+ }
+ }
return;
- case PREINCREMENT_EXPR:
case POSTINCREMENT_EXPR:
+ if (code == OMP_ATOMIC_CAPTURE_NEW && !structured_block)
+ code = OMP_ATOMIC_CAPTURE_OLD;
+ /* FALLTHROUGH */
+ case PREINCREMENT_EXPR:
lhs = TREE_OPERAND (lhs, 0);
- code = PLUS_EXPR;
+ opcode = PLUS_EXPR;
rhs = integer_one_node;
break;
- case PREDECREMENT_EXPR:
case POSTDECREMENT_EXPR:
+ if (code == OMP_ATOMIC_CAPTURE_NEW && !structured_block)
+ code = OMP_ATOMIC_CAPTURE_OLD;
+ /* FALLTHROUGH */
+ case PREDECREMENT_EXPR:
lhs = TREE_OPERAND (lhs, 0);
- code = MINUS_EXPR;
+ opcode = MINUS_EXPR;
rhs = integer_one_node;
break;
/* This is pre or post increment. */
rhs = TREE_OPERAND (lhs, 1);
lhs = TREE_OPERAND (lhs, 0);
- code = NOP_EXPR;
+ opcode = NOP_EXPR;
+ if (code == OMP_ATOMIC_CAPTURE_NEW
+ && !structured_block
+ && TREE_CODE (orig_lhs) == COMPOUND_EXPR)
+ code = OMP_ATOMIC_CAPTURE_OLD;
break;
}
if (TREE_CODE (TREE_OPERAND (lhs, 1)) == TRUTH_NOT_EXPR
/* This is pre or post decrement. */
rhs = TREE_OPERAND (lhs, 1);
lhs = TREE_OPERAND (lhs, 0);
- code = NOP_EXPR;
+ opcode = NOP_EXPR;
+ if (code == OMP_ATOMIC_CAPTURE_NEW
+ && !structured_block
+ && TREE_CODE (orig_lhs) == COMPOUND_EXPR)
+ code = OMP_ATOMIC_CAPTURE_OLD;
break;
}
}
switch (c_parser_peek_token (parser)->type)
{
case CPP_MULT_EQ:
- code = MULT_EXPR;
+ opcode = MULT_EXPR;
break;
case CPP_DIV_EQ:
- code = TRUNC_DIV_EXPR;
+ opcode = TRUNC_DIV_EXPR;
break;
case CPP_PLUS_EQ:
- code = PLUS_EXPR;
+ opcode = PLUS_EXPR;
break;
case CPP_MINUS_EQ:
- code = MINUS_EXPR;
+ opcode = MINUS_EXPR;
break;
case CPP_LSHIFT_EQ:
- code = LSHIFT_EXPR;
+ opcode = LSHIFT_EXPR;
break;
case CPP_RSHIFT_EQ:
- code = RSHIFT_EXPR;
+ opcode = RSHIFT_EXPR;
break;
case CPP_AND_EQ:
- code = BIT_AND_EXPR;
+ opcode = BIT_AND_EXPR;
break;
case CPP_OR_EQ:
- code = BIT_IOR_EXPR;
+ opcode = BIT_IOR_EXPR;
break;
case CPP_XOR_EQ:
- code = BIT_XOR_EXPR;
+ opcode = BIT_XOR_EXPR;
break;
+ case CPP_EQ:
+ if (structured_block || code == OMP_ATOMIC)
+ {
+ location_t aloc = c_parser_peek_token (parser)->location;
+ location_t rhs_loc;
+ enum c_parser_prec oprec = PREC_NONE;
+
+ c_parser_consume_token (parser);
+ rhs1 = c_parser_unary_expression (parser).value;
+ rhs1 = c_fully_fold (rhs1, false, NULL);
+ if (rhs1 == error_mark_node)
+ goto saw_error;
+ switch (c_parser_peek_token (parser)->type)
+ {
+ case CPP_SEMICOLON:
+ if (code == OMP_ATOMIC_CAPTURE_NEW)
+ {
+ code = OMP_ATOMIC_CAPTURE_OLD;
+ v = lhs;
+ lhs = NULL_TREE;
+ lhs1 = rhs1;
+ rhs1 = NULL_TREE;
+ c_parser_consume_token (parser);
+ goto restart;
+ }
+ c_parser_error (parser,
+ "invalid form of %<#pragma omp atomic%>");
+ goto saw_error;
+ case CPP_MULT:
+ opcode = MULT_EXPR;
+ oprec = PREC_MULT;
+ break;
+ case CPP_DIV:
+ opcode = TRUNC_DIV_EXPR;
+ oprec = PREC_MULT;
+ break;
+ case CPP_PLUS:
+ opcode = PLUS_EXPR;
+ oprec = PREC_ADD;
+ break;
+ case CPP_MINUS:
+ opcode = MINUS_EXPR;
+ oprec = PREC_ADD;
+ break;
+ case CPP_LSHIFT:
+ opcode = LSHIFT_EXPR;
+ oprec = PREC_SHIFT;
+ break;
+ case CPP_RSHIFT:
+ opcode = RSHIFT_EXPR;
+ oprec = PREC_SHIFT;
+ break;
+ case CPP_AND:
+ opcode = BIT_AND_EXPR;
+ oprec = PREC_BITAND;
+ break;
+ case CPP_OR:
+ opcode = BIT_IOR_EXPR;
+ oprec = PREC_BITOR;
+ break;
+ case CPP_XOR:
+ opcode = BIT_XOR_EXPR;
+ oprec = PREC_BITXOR;
+ break;
+ default:
+ c_parser_error (parser,
+ "invalid operator for %<#pragma omp atomic%>");
+ goto saw_error;
+ }
+ loc = aloc;
+ c_parser_consume_token (parser);
+ rhs_loc = c_parser_peek_token (parser)->location;
+ if (commutative_tree_code (opcode))
+ oprec = (enum c_parser_prec) (oprec - 1);
+ rhs_expr = c_parser_binary_expression (parser, NULL, oprec);
+ rhs_expr = default_function_array_read_conversion (rhs_loc,
+ rhs_expr);
+ rhs = rhs_expr.value;
+ rhs = c_fully_fold (rhs, false, NULL);
+ goto stmt_done;
+ }
+ /* FALLTHROUGH */
default:
c_parser_error (parser,
"invalid operator for %<#pragma omp atomic%>");
rhs = c_fully_fold (rhs, false, NULL);
break;
}
- stmt = c_finish_omp_atomic (loc, code, lhs, rhs);
+stmt_done:
+ if (structured_block && code == OMP_ATOMIC_CAPTURE_NEW)
+ {
+ if (!c_parser_require (parser, CPP_SEMICOLON, "expected %<;%>"))
+ goto saw_error;
+ v = c_parser_unary_expression (parser).value;
+ v = c_fully_fold (v, false, NULL);
+ if (v == error_mark_node)
+ goto saw_error;
+ if (!c_parser_require (parser, CPP_EQ, "expected %<=%>"))
+ goto saw_error;
+ lhs1 = c_parser_unary_expression (parser).value;
+ lhs1 = c_fully_fold (lhs1, false, NULL);
+ if (lhs1 == error_mark_node)
+ goto saw_error;
+ }
+ if (structured_block)
+ {
+ c_parser_skip_until_found (parser, CPP_SEMICOLON, "expected %<;%>");
+ c_parser_require (parser, CPP_CLOSE_BRACE, "expected %<}%>");
+ }
+done:
+ stmt = c_finish_omp_atomic (loc, code, opcode, lhs, rhs, v, lhs1, rhs1);
if (stmt != error_mark_node)
add_stmt (stmt);
- c_parser_skip_until_found (parser, CPP_SEMICOLON, "expected %<;%>");
+
+ if (!structured_block)
+ c_parser_skip_until_found (parser, CPP_SEMICOLON, "expected %<;%>");
}
if (c_parser_next_token_is_not (parser, CPP_SEMICOLON))
{
location_t cond_loc = c_parser_peek_token (parser)->location;
- struct c_expr cond_expr = c_parser_binary_expression (parser, NULL);
+ struct c_expr cond_expr = c_parser_binary_expression (parser, NULL,
+ PREC_NONE);
cond = cond_expr.value;
cond = c_objc_common_truthvalue_conversion (cond_loc, cond);
| (1u << PRAGMA_OMP_CLAUSE_DEFAULT) \
| (1u << PRAGMA_OMP_CLAUSE_PRIVATE) \
| (1u << PRAGMA_OMP_CLAUSE_FIRSTPRIVATE) \
- | (1u << PRAGMA_OMP_CLAUSE_SHARED))
+ | (1u << PRAGMA_OMP_CLAUSE_SHARED) \
+ | (1u << PRAGMA_OMP_CLAUSE_FINAL) \
+ | (1u << PRAGMA_OMP_CLAUSE_MERGEABLE))
static tree
c_parser_omp_task (location_t loc, c_parser *parser)
c_finish_omp_taskwait (loc);
}
+/* OpenMP 3.1:
+ # pragma omp taskyield new-line
+*/
+
+static void
+c_parser_omp_taskyield (c_parser *parser)
+{
+ location_t loc = c_parser_peek_token (parser)->location;
+ c_parser_consume_pragma (parser);
+ c_parser_skip_to_pragma_eol (parser);
+
+ c_finish_omp_taskyield (loc);
+}
+
/* Main entry point to parsing most OpenMP pragmas. */
static void
case PLUS_EXPR:
case MULT_EXPR:
case MINUS_EXPR:
+ case MIN_EXPR:
+ case MAX_EXPR:
break;
case BIT_AND_EXPR:
r_name = "&";
case OMP_CLAUSE_DEFAULT:
case OMP_CLAUSE_UNTIED:
case OMP_CLAUSE_COLLAPSE:
+ case OMP_CLAUSE_FINAL:
+ case OMP_CLAUSE_MERGEABLE:
pc = &OMP_CLAUSE_CHAIN (c);
continue;
case OMP_CLAUSE_DEFAULT_UNSPECIFIED:
break;
case OMP_CLAUSE_DEFAULT_SHARED:
+ /* const vars may be specified in firstprivate clause. */
+ if (OMP_CLAUSE_CODE (c) == OMP_CLAUSE_FIRSTPRIVATE
+ && TREE_READONLY (t))
+ break;
share_name = "shared";
break;
case OMP_CLAUSE_DEFAULT_PRIVATE:
+2011-08-02 Jakub Jelinek <jakub@redhat.com>
+
+ * cp-tree.h (finish_omp_atomic): Adjust prototype.
+ (cxx_omp_const_qual_no_mutable): New prototype.
+ (finish_omp_taskyield): New prototype.
+ * parser.c (cp_parser_omp_atomic): (cp_parser_omp_atomic): Handle
+ parsing OpenMP 3.1 atomics. Adjust finish_omp_atomic caller.
+ (cp_parser_omp_clause_name): Handle final and mergeable clauses.
+ (cp_parser_omp_clause_final, cp_parser_omp_clause_mergeable): New
+ functions.
+ (cp_parser_omp_all_clauses): Handle PRAGMA_OMP_CLAUSE_FINAL
+ and PRAGMA_OMP_CLAUSE_MERGEABLE.
+ (OMP_TASK_CLAUSE_MASK): Allow final and mergeable clauses.
+ (cp_parser_omp_taskyield): New function.
+ (cp_parser_pragma): Handle PRAGMA_OMP_TASKYIELD.
+ (cp_parser_omp_clause_reduction): Handle min and max.
+ * pt.c (tsubst_expr) <case OMP_ATOMIC>: Handle OpenMP 3.1 atomics.
+ (tsubst_omp_clauses): Handle OMP_CLAUSE_FINAL and
+ OMP_CLAUSE_MERGEABLE.
+ * semantics.c (finish_omp_atomic): Add OPCODE, V, LHS1 and RHS1
+ arguments. Handle OpenMP 3.1 atomics. Adjust c_finish_omp_atomic
+ caller.
+ (finish_omp_clauses): Don't complain about const qualified
+ predetermined vars and static data members in firstprivate clause.
+ Handle OMP_CLAUSE_FINAL and OMP_CLAUSE_MERGEABLE. Handle MIN_EXPR
+ and MAX_EXPR.
+ (finish_omp_taskyield): New function.
+ * cp-gimplify.c (cxx_omp_const_qual_no_mutable): New function.
+ (cxx_omp_predetermined_sharing): Use it.
+
2011-08-02 Jason Merrill <jason@redhat.com>
* call.c (build_call_a): Also check at_function_scope_p.
return is_invisiref_parm (decl);
}
-/* True if OpenMP sharing attribute of DECL is predetermined. */
-
-enum omp_clause_default_kind
-cxx_omp_predetermined_sharing (tree decl)
+/* Return true if DECL is const qualified var having no mutable member. */
+bool
+cxx_omp_const_qual_no_mutable (tree decl)
{
- tree type;
-
- /* Static data members are predetermined as shared. */
- if (TREE_STATIC (decl))
- {
- tree ctx = CP_DECL_CONTEXT (decl);
- if (TYPE_P (ctx) && MAYBE_CLASS_TYPE_P (ctx))
- return OMP_CLAUSE_DEFAULT_SHARED;
- }
-
- type = TREE_TYPE (decl);
+ tree type = TREE_TYPE (decl);
if (TREE_CODE (type) == REFERENCE_TYPE)
{
if (!is_invisiref_parm (decl))
- return OMP_CLAUSE_DEFAULT_UNSPECIFIED;
+ return false;
type = TREE_TYPE (type);
if (TREE_CODE (decl) == RESULT_DECL && DECL_NAME (decl))
}
if (type == error_mark_node)
- return OMP_CLAUSE_DEFAULT_UNSPECIFIED;
+ return false;
/* Variables with const-qualified type having no mutable member
are predetermined shared. */
if (TYPE_READONLY (type) && !cp_has_mutable_p (type))
+ return true;
+
+ return false;
+}
+
+/* True if OpenMP sharing attribute of DECL is predetermined. */
+
+enum omp_clause_default_kind
+cxx_omp_predetermined_sharing (tree decl)
+{
+ /* Static data members are predetermined shared. */
+ if (TREE_STATIC (decl))
+ {
+ tree ctx = CP_DECL_CONTEXT (decl);
+ if (TYPE_P (ctx) && MAYBE_CLASS_TYPE_P (ctx))
+ return OMP_CLAUSE_DEFAULT_SHARED;
+ }
+
+ /* Const qualified vars having no mutable member are predetermined
+ shared. */
+ if (cxx_omp_const_qual_no_mutable (decl))
return OMP_CLAUSE_DEFAULT_SHARED;
return OMP_CLAUSE_DEFAULT_UNSPECIFIED;
extern tree finish_omp_task (tree, tree);
extern tree finish_omp_for (location_t, tree, tree,
tree, tree, tree, tree, tree);
-extern void finish_omp_atomic (enum tree_code, tree, tree);
+extern void finish_omp_atomic (enum tree_code, enum tree_code,
+ tree, tree, tree, tree, tree);
extern void finish_omp_barrier (void);
extern void finish_omp_flush (void);
extern void finish_omp_taskwait (void);
+extern void finish_omp_taskyield (void);
extern bool cxx_omp_create_clause_info (tree, tree, bool, bool, bool);
extern tree baselink_for_fns (tree);
extern void finish_static_assert (tree, tree, location_t,
extern int cp_gimplify_expr (tree *, gimple_seq *,
gimple_seq *);
extern void cp_genericize (tree);
+extern bool cxx_omp_const_qual_no_mutable (tree);
extern enum omp_clause_default_kind cxx_omp_predetermined_sharing (tree);
extern tree cxx_omp_clause_default_ctor (tree, tree, tree);
extern tree cxx_omp_clause_copy_ctor (tree, tree, tree);
result = PRAGMA_OMP_CLAUSE_COPYPRIVATE;
break;
case 'f':
- if (!strcmp ("firstprivate", p))
+ if (!strcmp ("final", p))
+ result = PRAGMA_OMP_CLAUSE_FINAL;
+ else if (!strcmp ("firstprivate", p))
result = PRAGMA_OMP_CLAUSE_FIRSTPRIVATE;
break;
case 'l':
if (!strcmp ("lastprivate", p))
result = PRAGMA_OMP_CLAUSE_LASTPRIVATE;
break;
+ case 'm':
+ if (!strcmp ("mergeable", p))
+ result = PRAGMA_OMP_CLAUSE_MERGEABLE;
+ break;
case 'n':
if (!strcmp ("nowait", p))
result = PRAGMA_OMP_CLAUSE_NOWAIT;
return c;
}
+/* OpenMP 3.1:
+ final ( expression ) */
+
+static tree
+cp_parser_omp_clause_final (cp_parser *parser, tree list, location_t location)
+{
+ tree t, c;
+
+ if (!cp_parser_require (parser, CPP_OPEN_PAREN, RT_OPEN_PAREN))
+ return list;
+
+ t = cp_parser_condition (parser);
+
+ if (t == error_mark_node
+ || !cp_parser_require (parser, CPP_CLOSE_PAREN, RT_CLOSE_PAREN))
+ cp_parser_skip_to_closing_parenthesis (parser, /*recovering=*/true,
+ /*or_comma=*/false,
+ /*consume_paren=*/true);
+
+ check_no_duplicate_clause (list, OMP_CLAUSE_FINAL, "final", location);
+
+ c = build_omp_clause (location, OMP_CLAUSE_FINAL);
+ OMP_CLAUSE_FINAL_EXPR (c) = t;
+ OMP_CLAUSE_CHAIN (c) = list;
+
+ return c;
+}
+
/* OpenMP 2.5:
if ( expression ) */
return c;
}
+/* OpenMP 3.1:
+ mergeable */
+
+static tree
+cp_parser_omp_clause_mergeable (cp_parser *parser ATTRIBUTE_UNUSED,
+ tree list, location_t location)
+{
+ tree c;
+
+ check_no_duplicate_clause (list, OMP_CLAUSE_MERGEABLE, "mergeable",
+ location);
+
+ c = build_omp_clause (location, OMP_CLAUSE_MERGEABLE);
+ OMP_CLAUSE_CHAIN (c) = list;
+ return c;
+}
+
/* OpenMP 2.5:
nowait */
reduction ( reduction-operator : variable-list )
reduction-operator:
- One of: + * - & ^ | && || */
+ One of: + * - & ^ | && ||
+
+ OpenMP 3.1:
+
+ reduction-operator:
+ One of: + * - & ^ | && || min max */
static tree
cp_parser_omp_clause_reduction (cp_parser *parser, tree list)
case CPP_OR_OR:
code = TRUTH_ORIF_EXPR;
break;
+ case CPP_NAME:
+ {
+ tree id = cp_lexer_peek_token (parser->lexer)->u.value;
+ const char *p = IDENTIFIER_POINTER (id);
+
+ if (strcmp (p, "min") == 0)
+ {
+ code = MIN_EXPR;
+ break;
+ }
+ if (strcmp (p, "max") == 0)
+ {
+ code = MAX_EXPR;
+ break;
+ }
+ }
+ /* FALLTHROUGH */
default:
cp_parser_error (parser, "expected %<+%>, %<*%>, %<-%>, %<&%>, %<^%>, "
- "%<|%>, %<&&%>, or %<||%>");
+ "%<|%>, %<&&%>, %<||%>, %<min%> or %<max%>");
resync_fail:
cp_parser_skip_to_closing_parenthesis (parser, /*recovering=*/true,
/*or_comma=*/false,
token->location);
c_name = "default";
break;
+ case PRAGMA_OMP_CLAUSE_FINAL:
+ clauses = cp_parser_omp_clause_final (parser, clauses, token->location);
+ c_name = "final";
+ break;
case PRAGMA_OMP_CLAUSE_FIRSTPRIVATE:
clauses = cp_parser_omp_var_list (parser, OMP_CLAUSE_FIRSTPRIVATE,
clauses);
clauses);
c_name = "lastprivate";
break;
+ case PRAGMA_OMP_CLAUSE_MERGEABLE:
+ clauses = cp_parser_omp_clause_mergeable (parser, clauses,
+ token->location);
+ c_name = "mergeable";
+ break;
case PRAGMA_OMP_CLAUSE_NOWAIT:
clauses = cp_parser_omp_clause_nowait (parser, clauses, token->location);
c_name = "nowait";
binop:
+, *, -, /, &, ^, |, <<, >>
- where x is an lvalue expression with scalar type. */
+ where x is an lvalue expression with scalar type.
+
+ OpenMP 3.1:
+ # pragma omp atomic new-line
+ update-stmt
+
+ # pragma omp atomic read new-line
+ read-stmt
+
+ # pragma omp atomic write new-line
+ write-stmt
+
+ # pragma omp atomic update new-line
+ update-stmt
+
+ # pragma omp atomic capture new-line
+ capture-stmt
+
+ # pragma omp atomic capture new-line
+ capture-block
+
+ read-stmt:
+ v = x
+ write-stmt:
+ x = expr
+ update-stmt:
+ expression-stmt | x = x binop expr
+ capture-stmt:
+ v = x binop= expr | v = x++ | v = ++x | v = x-- | v = --x
+ capture-block:
+ { v = x; update-stmt; } | { update-stmt; v = x; }
+
+ where x and v are lvalue expressions with scalar type. */
static void
cp_parser_omp_atomic (cp_parser *parser, cp_token *pragma_tok)
{
- tree lhs, rhs;
- enum tree_code code;
+ tree lhs = NULL_TREE, rhs = NULL_TREE, v = NULL_TREE, lhs1 = NULL_TREE;
+ tree rhs1 = NULL_TREE, orig_lhs;
+ enum tree_code code = OMP_ATOMIC, opcode = NOP_EXPR;
+ bool structured_block = false;
+
+ if (cp_lexer_next_token_is (parser->lexer, CPP_NAME))
+ {
+ tree id = cp_lexer_peek_token (parser->lexer)->u.value;
+ const char *p = IDENTIFIER_POINTER (id);
+ if (!strcmp (p, "read"))
+ code = OMP_ATOMIC_READ;
+ else if (!strcmp (p, "write"))
+ code = NOP_EXPR;
+ else if (!strcmp (p, "update"))
+ code = OMP_ATOMIC;
+ else if (!strcmp (p, "capture"))
+ code = OMP_ATOMIC_CAPTURE_NEW;
+ else
+ p = NULL;
+ if (p)
+ cp_lexer_consume_token (parser->lexer);
+ }
cp_parser_require_pragma_eol (parser, pragma_tok);
+ switch (code)
+ {
+ case OMP_ATOMIC_READ:
+ case NOP_EXPR: /* atomic write */
+ v = cp_parser_unary_expression (parser, /*address_p=*/false,
+ /*cast_p=*/false, NULL);
+ if (v == error_mark_node)
+ goto saw_error;
+ if (!cp_parser_require (parser, CPP_EQ, RT_EQ))
+ goto saw_error;
+ if (code == NOP_EXPR)
+ lhs = cp_parser_expression (parser, /*cast_p=*/false, NULL);
+ else
+ lhs = cp_parser_unary_expression (parser, /*address_p=*/false,
+ /*cast_p=*/false, NULL);
+ if (lhs == error_mark_node)
+ goto saw_error;
+ if (code == NOP_EXPR)
+ {
+ /* atomic write is represented by OMP_ATOMIC with NOP_EXPR
+ opcode. */
+ code = OMP_ATOMIC;
+ rhs = lhs;
+ lhs = v;
+ v = NULL_TREE;
+ }
+ goto done;
+ case OMP_ATOMIC_CAPTURE_NEW:
+ if (cp_lexer_next_token_is (parser->lexer, CPP_OPEN_BRACE))
+ {
+ cp_lexer_consume_token (parser->lexer);
+ structured_block = true;
+ }
+ else
+ {
+ v = cp_parser_unary_expression (parser, /*address_p=*/false,
+ /*cast_p=*/false, NULL);
+ if (v == error_mark_node)
+ goto saw_error;
+ if (!cp_parser_require (parser, CPP_EQ, RT_EQ))
+ goto saw_error;
+ }
+ default:
+ break;
+ }
+
+restart:
lhs = cp_parser_unary_expression (parser, /*address_p=*/false,
/*cast_p=*/false, NULL);
+ orig_lhs = lhs;
switch (TREE_CODE (lhs))
{
case ERROR_MARK:
goto saw_error;
- case PREINCREMENT_EXPR:
case POSTINCREMENT_EXPR:
+ if (code == OMP_ATOMIC_CAPTURE_NEW && !structured_block)
+ code = OMP_ATOMIC_CAPTURE_OLD;
+ /* FALLTHROUGH */
+ case PREINCREMENT_EXPR:
lhs = TREE_OPERAND (lhs, 0);
- code = PLUS_EXPR;
+ opcode = PLUS_EXPR;
rhs = integer_one_node;
break;
- case PREDECREMENT_EXPR:
case POSTDECREMENT_EXPR:
+ if (code == OMP_ATOMIC_CAPTURE_NEW && !structured_block)
+ code = OMP_ATOMIC_CAPTURE_OLD;
+ /* FALLTHROUGH */
+ case PREDECREMENT_EXPR:
lhs = TREE_OPERAND (lhs, 0);
- code = MINUS_EXPR;
+ opcode = MINUS_EXPR;
rhs = integer_one_node;
break;
case MODIFY_EXPR:
if (TREE_CODE (lhs) == MODIFY_EXPR
&& TREE_CODE (TREE_TYPE (TREE_OPERAND (lhs, 0))) == BOOLEAN_TYPE)
- {
- /* Undo effects of boolean_increment. */
- if (integer_onep (TREE_OPERAND (lhs, 1)))
- {
- /* This is pre or post increment. */
- rhs = TREE_OPERAND (lhs, 1);
- lhs = TREE_OPERAND (lhs, 0);
- code = NOP_EXPR;
- break;
- }
- }
+ {
+ /* Undo effects of boolean_increment. */
+ if (integer_onep (TREE_OPERAND (lhs, 1)))
+ {
+ /* This is pre or post increment. */
+ rhs = TREE_OPERAND (lhs, 1);
+ lhs = TREE_OPERAND (lhs, 0);
+ opcode = NOP_EXPR;
+ if (code == OMP_ATOMIC_CAPTURE_NEW
+ && !structured_block
+ && TREE_CODE (orig_lhs) == COMPOUND_EXPR)
+ code = OMP_ATOMIC_CAPTURE_OLD;
+ break;
+ }
+ }
/* FALLTHRU */
default:
switch (cp_lexer_peek_token (parser->lexer)->type)
{
case CPP_MULT_EQ:
- code = MULT_EXPR;
+ opcode = MULT_EXPR;
break;
case CPP_DIV_EQ:
- code = TRUNC_DIV_EXPR;
+ opcode = TRUNC_DIV_EXPR;
break;
case CPP_PLUS_EQ:
- code = PLUS_EXPR;
+ opcode = PLUS_EXPR;
break;
case CPP_MINUS_EQ:
- code = MINUS_EXPR;
+ opcode = MINUS_EXPR;
break;
case CPP_LSHIFT_EQ:
- code = LSHIFT_EXPR;
+ opcode = LSHIFT_EXPR;
break;
case CPP_RSHIFT_EQ:
- code = RSHIFT_EXPR;
+ opcode = RSHIFT_EXPR;
break;
case CPP_AND_EQ:
- code = BIT_AND_EXPR;
+ opcode = BIT_AND_EXPR;
break;
case CPP_OR_EQ:
- code = BIT_IOR_EXPR;
+ opcode = BIT_IOR_EXPR;
break;
case CPP_XOR_EQ:
- code = BIT_XOR_EXPR;
+ opcode = BIT_XOR_EXPR;
break;
+ case CPP_EQ:
+ if (structured_block || code == OMP_ATOMIC)
+ {
+ enum cp_parser_prec oprec;
+ cp_token *token;
+ cp_lexer_consume_token (parser->lexer);
+ rhs1 = cp_parser_unary_expression (parser, /*address_p=*/false,
+ /*cast_p=*/false, NULL);
+ if (rhs1 == error_mark_node)
+ goto saw_error;
+ token = cp_lexer_peek_token (parser->lexer);
+ switch (token->type)
+ {
+ case CPP_SEMICOLON:
+ if (code == OMP_ATOMIC_CAPTURE_NEW)
+ {
+ code = OMP_ATOMIC_CAPTURE_OLD;
+ v = lhs;
+ lhs = NULL_TREE;
+ lhs1 = rhs1;
+ rhs1 = NULL_TREE;
+ cp_lexer_consume_token (parser->lexer);
+ goto restart;
+ }
+ cp_parser_error (parser,
+ "invalid form of %<#pragma omp atomic%>");
+ goto saw_error;
+ case CPP_MULT:
+ opcode = MULT_EXPR;
+ break;
+ case CPP_DIV:
+ opcode = TRUNC_DIV_EXPR;
+ break;
+ case CPP_PLUS:
+ opcode = PLUS_EXPR;
+ break;
+ case CPP_MINUS:
+ opcode = MINUS_EXPR;
+ break;
+ case CPP_LSHIFT:
+ opcode = LSHIFT_EXPR;
+ break;
+ case CPP_RSHIFT:
+ opcode = RSHIFT_EXPR;
+ break;
+ case CPP_AND:
+ opcode = BIT_AND_EXPR;
+ break;
+ case CPP_OR:
+ opcode = BIT_IOR_EXPR;
+ break;
+ case CPP_XOR:
+ opcode = BIT_XOR_EXPR;
+ break;
+ default:
+ cp_parser_error (parser,
+ "invalid operator for %<#pragma omp atomic%>");
+ goto saw_error;
+ }
+ oprec = TOKEN_PRECEDENCE (token);
+ gcc_assert (oprec != PREC_NOT_OPERATOR);
+ if (commutative_tree_code (opcode))
+ oprec = (enum cp_parser_prec) (oprec - 1);
+ cp_lexer_consume_token (parser->lexer);
+ rhs = cp_parser_binary_expression (parser, false, false,
+ oprec, NULL);
+ if (rhs == error_mark_node)
+ goto saw_error;
+ goto stmt_done;
+ }
+ /* FALLTHROUGH */
default:
cp_parser_error (parser,
"invalid operator for %<#pragma omp atomic%>");
goto saw_error;
break;
}
- finish_omp_atomic (code, lhs, rhs);
- cp_parser_consume_semicolon_at_end_of_statement (parser);
+stmt_done:
+ if (structured_block && code == OMP_ATOMIC_CAPTURE_NEW)
+ {
+ if (!cp_parser_require (parser, CPP_SEMICOLON, RT_SEMICOLON))
+ goto saw_error;
+ v = cp_parser_unary_expression (parser, /*address_p=*/false,
+ /*cast_p=*/false, NULL);
+ if (v == error_mark_node)
+ goto saw_error;
+ if (!cp_parser_require (parser, CPP_EQ, RT_EQ))
+ goto saw_error;
+ lhs1 = cp_parser_unary_expression (parser, /*address_p=*/false,
+ /*cast_p=*/false, NULL);
+ if (lhs1 == error_mark_node)
+ goto saw_error;
+ }
+ if (structured_block)
+ {
+ cp_parser_consume_semicolon_at_end_of_statement (parser);
+ cp_parser_require (parser, CPP_CLOSE_BRACE, RT_CLOSE_BRACE);
+ }
+done:
+ finish_omp_atomic (code, opcode, lhs, rhs, v, lhs1, rhs1);
+ if (!structured_block)
+ cp_parser_consume_semicolon_at_end_of_statement (parser);
return;
saw_error:
cp_parser_skip_to_end_of_block_or_statement (parser);
+ if (structured_block)
+ {
+ if (cp_lexer_next_token_is (parser->lexer, CPP_CLOSE_BRACE))
+ cp_lexer_consume_token (parser->lexer);
+ else if (code == OMP_ATOMIC_CAPTURE_NEW)
+ {
+ cp_parser_skip_to_end_of_block_or_statement (parser);
+ if (cp_lexer_next_token_is (parser->lexer, CPP_CLOSE_BRACE))
+ cp_lexer_consume_token (parser->lexer);
+ }
+ }
}
| (1u << PRAGMA_OMP_CLAUSE_DEFAULT) \
| (1u << PRAGMA_OMP_CLAUSE_PRIVATE) \
| (1u << PRAGMA_OMP_CLAUSE_FIRSTPRIVATE) \
- | (1u << PRAGMA_OMP_CLAUSE_SHARED))
+ | (1u << PRAGMA_OMP_CLAUSE_SHARED) \
+ | (1u << PRAGMA_OMP_CLAUSE_FINAL) \
+ | (1u << PRAGMA_OMP_CLAUSE_MERGEABLE))
static tree
cp_parser_omp_task (cp_parser *parser, cp_token *pragma_tok)
finish_omp_taskwait ();
}
+/* OpenMP 3.1:
+ # pragma omp taskyield new-line */
+
+static void
+cp_parser_omp_taskyield (cp_parser *parser, cp_token *pragma_tok)
+{
+ cp_parser_require_pragma_eol (parser, pragma_tok);
+ finish_omp_taskyield ();
+}
+
/* OpenMP 2.5:
# pragma omp threadprivate (variable-list) */
}
break;
+ case PRAGMA_OMP_TASKYIELD:
+ switch (context)
+ {
+ case pragma_compound:
+ cp_parser_omp_taskyield (parser, pragma_tok);
+ return false;
+ case pragma_stmt:
+ error_at (pragma_tok->location,
+ "%<#pragma omp taskyield%> may only be "
+ "used in compound statements");
+ break;
+ default:
+ goto bad_stmt;
+ }
+ break;
+
case PRAGMA_OMP_THREADPRIVATE:
cp_parser_omp_threadprivate (parser, pragma_tok);
return false;
case OMP_CLAUSE_NUM_THREADS:
case OMP_CLAUSE_SCHEDULE:
case OMP_CLAUSE_COLLAPSE:
+ case OMP_CLAUSE_FINAL:
OMP_CLAUSE_OPERAND (nc, 0)
= tsubst_expr (OMP_CLAUSE_OPERAND (oc, 0), args, complain,
in_decl, /*integral_constant_expression_p=*/false);
case OMP_CLAUSE_ORDERED:
case OMP_CLAUSE_DEFAULT:
case OMP_CLAUSE_UNTIED:
+ case OMP_CLAUSE_MERGEABLE:
break;
default:
gcc_unreachable ();
case OMP_ATOMIC:
gcc_assert (OMP_ATOMIC_DEPENDENT_P (t));
- {
- tree op1 = TREE_OPERAND (t, 1);
- tree lhs = RECUR (TREE_OPERAND (op1, 0));
- tree rhs = RECUR (TREE_OPERAND (op1, 1));
- finish_omp_atomic (TREE_CODE (op1), lhs, rhs);
- }
+ if (TREE_CODE (TREE_OPERAND (t, 1)) != MODIFY_EXPR)
+ {
+ tree op1 = TREE_OPERAND (t, 1);
+ tree rhs1 = NULL_TREE;
+ tree lhs, rhs;
+ if (TREE_CODE (op1) == COMPOUND_EXPR)
+ {
+ rhs1 = RECUR (TREE_OPERAND (op1, 0));
+ op1 = TREE_OPERAND (op1, 1);
+ }
+ lhs = RECUR (TREE_OPERAND (op1, 0));
+ rhs = RECUR (TREE_OPERAND (op1, 1));
+ finish_omp_atomic (OMP_ATOMIC, TREE_CODE (op1), lhs, rhs,
+ NULL_TREE, NULL_TREE, rhs1);
+ }
+ else
+ {
+ tree op1 = TREE_OPERAND (t, 1);
+ tree v = NULL_TREE, lhs, rhs = NULL_TREE, lhs1 = NULL_TREE;
+ tree rhs1 = NULL_TREE;
+ enum tree_code code = TREE_CODE (TREE_OPERAND (op1, 1));
+ enum tree_code opcode = NOP_EXPR;
+ if (code == OMP_ATOMIC_READ)
+ {
+ v = RECUR (TREE_OPERAND (op1, 0));
+ lhs = RECUR (TREE_OPERAND (TREE_OPERAND (op1, 1), 0));
+ }
+ else if (code == OMP_ATOMIC_CAPTURE_OLD
+ || code == OMP_ATOMIC_CAPTURE_NEW)
+ {
+ tree op11 = TREE_OPERAND (TREE_OPERAND (op1, 1), 1);
+ v = RECUR (TREE_OPERAND (op1, 0));
+ lhs1 = RECUR (TREE_OPERAND (TREE_OPERAND (op1, 1), 0));
+ if (TREE_CODE (op11) == COMPOUND_EXPR)
+ {
+ rhs1 = RECUR (TREE_OPERAND (op11, 0));
+ op11 = TREE_OPERAND (op11, 1);
+ }
+ lhs = RECUR (TREE_OPERAND (op11, 0));
+ rhs = RECUR (TREE_OPERAND (op11, 1));
+ opcode = TREE_CODE (op11);
+ }
+ else
+ {
+ code = OMP_ATOMIC;
+ lhs = RECUR (TREE_OPERAND (op1, 0));
+ rhs = RECUR (TREE_OPERAND (op1, 1));
+ }
+ finish_omp_atomic (code, opcode, lhs, rhs, v, lhs1, rhs1);
+ }
break;
case EXPR_PACK_EXPANSION:
OMP_CLAUSE_IF_EXPR (c) = t;
break;
+ case OMP_CLAUSE_FINAL:
+ t = OMP_CLAUSE_FINAL_EXPR (c);
+ t = maybe_convert_cond (t);
+ if (t == error_mark_node)
+ remove = true;
+ OMP_CLAUSE_FINAL_EXPR (c) = t;
+ break;
+
case OMP_CLAUSE_NUM_THREADS:
t = OMP_CLAUSE_NUM_THREADS_EXPR (c);
if (t == error_mark_node)
case OMP_CLAUSE_DEFAULT:
case OMP_CLAUSE_UNTIED:
case OMP_CLAUSE_COLLAPSE:
+ case OMP_CLAUSE_MERGEABLE:
break;
default:
case PLUS_EXPR:
case MULT_EXPR:
case MINUS_EXPR:
+ case MIN_EXPR:
+ case MAX_EXPR:
break;
default:
error ("%qE has invalid type for %<reduction(%s)%>",
case OMP_CLAUSE_DEFAULT_UNSPECIFIED:
break;
case OMP_CLAUSE_DEFAULT_SHARED:
+ /* const vars may be specified in firstprivate clause. */
+ if (OMP_CLAUSE_CODE (c) == OMP_CLAUSE_FIRSTPRIVATE
+ && cxx_omp_const_qual_no_mutable (t))
+ break;
share_name = "shared";
break;
case OMP_CLAUSE_DEFAULT_PRIVATE:
}
void
-finish_omp_atomic (enum tree_code code, tree lhs, tree rhs)
+finish_omp_atomic (enum tree_code code, enum tree_code opcode, tree lhs,
+ tree rhs, tree v, tree lhs1, tree rhs1)
{
tree orig_lhs;
tree orig_rhs;
+ tree orig_v;
+ tree orig_lhs1;
+ tree orig_rhs1;
bool dependent_p;
tree stmt;
orig_lhs = lhs;
orig_rhs = rhs;
+ orig_v = v;
+ orig_lhs1 = lhs1;
+ orig_rhs1 = rhs1;
dependent_p = false;
stmt = NULL_TREE;
if (processing_template_decl)
{
dependent_p = (type_dependent_expression_p (lhs)
- || type_dependent_expression_p (rhs));
+ || (rhs && type_dependent_expression_p (rhs))
+ || (v && type_dependent_expression_p (v))
+ || (lhs1 && type_dependent_expression_p (lhs1))
+ || (rhs1 && type_dependent_expression_p (rhs1)));
if (!dependent_p)
{
lhs = build_non_dependent_expr (lhs);
- rhs = build_non_dependent_expr (rhs);
+ if (rhs)
+ rhs = build_non_dependent_expr (rhs);
+ if (v)
+ v = build_non_dependent_expr (v);
+ if (lhs1)
+ lhs1 = build_non_dependent_expr (lhs1);
+ if (rhs1)
+ rhs1 = build_non_dependent_expr (rhs1);
}
}
if (!dependent_p)
{
- stmt = c_finish_omp_atomic (input_location, code, lhs, rhs);
+ stmt = c_finish_omp_atomic (input_location, code, opcode, lhs, rhs,
+ v, lhs1, rhs1);
if (stmt == error_mark_node)
return;
}
if (processing_template_decl)
- stmt = build2 (OMP_ATOMIC, void_type_node, integer_zero_node,
- build2 (code, void_type_node, orig_lhs, orig_rhs));
+ {
+ if (code == OMP_ATOMIC_READ)
+ {
+ stmt = build_min_nt (OMP_ATOMIC_READ, orig_lhs);
+ stmt = build2 (MODIFY_EXPR, void_type_node, orig_v, stmt);
+ }
+ else
+ {
+ if (opcode == NOP_EXPR)
+ stmt = build2 (MODIFY_EXPR, void_type_node, orig_lhs, orig_rhs);
+ else
+ stmt = build2 (opcode, void_type_node, orig_lhs, orig_rhs);
+ if (orig_rhs1)
+ stmt = build_min_nt (COMPOUND_EXPR, orig_rhs1, stmt);
+ if (code != OMP_ATOMIC)
+ {
+ stmt = build_min_nt (code, orig_lhs1, stmt);
+ stmt = build2 (MODIFY_EXPR, void_type_node, orig_v, stmt);
+ }
+ }
+ stmt = build2 (OMP_ATOMIC, void_type_node, integer_zero_node, stmt);
+ }
add_stmt (stmt);
}
release_tree_vector (vec);
finish_expr_stmt (stmt);
}
+
+void
+finish_omp_taskyield (void)
+{
+ tree fn = built_in_decls[BUILT_IN_GOMP_TASKYIELD];
+ VEC(tree,gc) *vec = make_tree_vector ();
+ tree stmt = finish_call_expr (fn, &vec, false, false, tf_warning_or_error);
+ release_tree_vector (vec);
+ finish_expr_stmt (stmt);
+}
\f
void
init_cp_semantics (void)
@code{OMP_CLAUSE_COPYPRIVATE}, @code{OMP_CLAUSE_IF},
@code{OMP_CLAUSE_NUM_THREADS}, @code{OMP_CLAUSE_SCHEDULE},
@code{OMP_CLAUSE_NOWAIT}, @code{OMP_CLAUSE_ORDERED},
-@code{OMP_CLAUSE_DEFAULT}, and @code{OMP_CLAUSE_REDUCTION}. Each code
+@code{OMP_CLAUSE_DEFAULT}, @code{OMP_CLAUSE_REDUCTION},
+@code{OMP_CLAUSE_COLLAPSE}, @code{OMP_CLAUSE_UNTIED},
+@code{OMP_CLAUSE_FINAL}, and @code{OMP_CLAUSE_MERGEABLE}. Each code
represents the corresponding OpenMP clause.
Clauses associated with the same directive are chained together
+2011-08-02 Jakub Jelinek <jakub@redhat.com>
+
+ PR fortran/46752
+ * cpp.c (cpp_define_builtins): Change _OPENMP to 201107.
+ * openmp.c (gfc_free_omp_clauses): Free also final_expr.
+ (OMP_CLAUSE_FINAL, OMP_CLAUSE_MERGEABLE): Define.
+ (gfc_match_omp_clauses): Handle parsing final and mergeable
+ clauses.
+ (OMP_TASK_CLAUSES): Allow final and mergeable clauses.
+ (gfc_match_omp_taskyield): New function.
+ (resolve_omp_clauses): Resolve final clause. Allow POINTERs and
+ Cray pointers in clauses other than REDUCTION.
+ (gfc_match_omp_atomic): Match optional
+ read/write/update/capture keywords after !$omp atomic.
+ (resolve_omp_atomic): Handle all OpenMP 3.1 atomic forms.
+ * dump-parse-tree.c (show_omp_node): Handle EXEC_OMP_TASKYIELD,
+ print final and mergeable clauses.
+ (show_code_node): Handle EXEC_OMP_TASKYIELD.
+ * trans-openmp.c (gfc_trans_omp_clauses): Handle final and
+ mergeable clauses.
+ (gfc_trans_omp_taskyield): New function.
+ (gfc_trans_omp_directive): Handle EXEC_OMP_TASKYIELD.
+ (gfc_trans_omp_atomic): Handle all OpenMP 3.1 atomic forms.
+ (gfc_omp_clause_copy_ctor): Handle non-allocated allocatable.
+ (gfc_omp_predetermined_sharing): Adjust comment.
+ * gfortran.h (gfc_statement): Add ST_OMP_TASKYIELD and
+ ST_OMP_END_ATOMIC.
+ (gfc_omp_clauses): Add final_expr and mergeable fields.
+ (gfc_exec_op): Add EXEC_OMP_TASKYIELD.
+ (gfc_omp_atomic_op): New enum typedef.
+ (struct gfc_code): Add ext.omp_atomic.
+ * trans.c (trans_code): Handle EXEC_OMP_TASKYIELD.
+ * frontend-passes.c (gfc_code_walker): Also walk final_expr.
+ * resolve.c (gfc_resolve_blocks, resolve_code): Handle
+ EXEC_OMP_TASKYIELD.
+ * st.c (gfc_free_statement): Likewise.
+ * match.h (gfc_match_omp_taskyield): New prototype.
+ * parse.c (decode_omp_directive): Handle taskyield directive.
+ Handle !$omp end atomic.
+ (case_executable): Add ST_OMP_TASKYIELD case.
+ (gfc_ascii_statement): Handle ST_OMP_TASKYIELD.
+ (parse_omp_atomic): Return gfc_statement instead of void.
+ For !$omp atomic capture parse two assignments instead of
+ just one and require !$omp end atomic afterwards, for
+ other !$omp atomic forms just allow !$omp end atomic at the
+ end.
+ (parse_omp_structured_block, parse_executable): Adjust
+ parse_omp_atomic callers.
+
+2011-08-02 Tobias Burnus <burnus@net-b.de>
+
+ * intrinsic.c (OMP_LIB): Updated openmp_version's
+ value to 201107.
+ * gfortran.texi (OpenMP): Update ref to OpenMP 3.1.
+ * intrinsic.texi (OpenMP Modules): Update ref to OpenMP 3.1;
+ remove deleted omp_integer_kind and omp_logical_kind constants.
+
2011-07-31 Janus Weil <janus@gcc.gnu.org>
PR fortran/49112
-/* Copyright (C) 2008, 2009, 2010 Free Software Foundation, Inc.
+/* Copyright (C) 2008, 2009, 2010, 2011 Free Software Foundation, Inc.
This file is part of GCC.
cpp_define (pfile, "_LANGUAGE_FORTRAN=1");
if (gfc_option.gfc_flag_openmp)
- cpp_define (pfile, "_OPENMP=200805");
+ cpp_define (pfile, "_OPENMP=201107");
/* The defines below are necessary for the TARGET_* macros.
case EXEC_OMP_SINGLE: name = "SINGLE"; break;
case EXEC_OMP_TASK: name = "TASK"; break;
case EXEC_OMP_TASKWAIT: name = "TASKWAIT"; break;
+ case EXEC_OMP_TASKYIELD: name = "TASKYIELD"; break;
case EXEC_OMP_WORKSHARE: name = "WORKSHARE"; break;
default:
gcc_unreachable ();
return;
case EXEC_OMP_BARRIER:
case EXEC_OMP_TASKWAIT:
+ case EXEC_OMP_TASKYIELD:
return;
default:
break;
show_expr (omp_clauses->if_expr);
fputc (')', dumpfile);
}
+ if (omp_clauses->final_expr)
+ {
+ fputs (" FINAL(", dumpfile);
+ show_expr (omp_clauses->final_expr);
+ fputc (')', dumpfile);
+ }
if (omp_clauses->num_threads)
{
fputs (" NUM_THREADS(", dumpfile);
fputs (" ORDERED", dumpfile);
if (omp_clauses->untied)
fputs (" UNTIED", dumpfile);
+ if (omp_clauses->mergeable)
+ fputs (" MERGEABLE", dumpfile);
if (omp_clauses->collapse)
fprintf (dumpfile, " COLLAPSE(%d)", omp_clauses->collapse);
for (list_type = 0; list_type < OMP_LIST_NUM; list_type++)
case EXEC_OMP_SINGLE:
case EXEC_OMP_TASK:
case EXEC_OMP_TASKWAIT:
+ case EXEC_OMP_TASKYIELD:
case EXEC_OMP_WORKSHARE:
show_omp_node (level, c);
break;
if (co->ext.omp_clauses)
{
WALK_SUBEXPR (co->ext.omp_clauses->if_expr);
+ WALK_SUBEXPR (co->ext.omp_clauses->final_expr);
WALK_SUBEXPR (co->ext.omp_clauses->num_threads);
WALK_SUBEXPR (co->ext.omp_clauses->chunk_size);
}
ST_WRITE, ST_ASSIGNMENT, ST_POINTER_ASSIGNMENT, ST_SELECT_CASE, ST_SEQUENCE,
ST_SIMPLE_IF, ST_STATEMENT_FUNCTION, ST_DERIVED_DECL, ST_LABEL_ASSIGNMENT,
ST_ENUM, ST_ENUMERATOR, ST_END_ENUM, ST_SELECT_TYPE, ST_TYPE_IS, ST_CLASS_IS,
- ST_OMP_ATOMIC, ST_OMP_BARRIER, ST_OMP_CRITICAL, ST_OMP_END_CRITICAL,
- ST_OMP_END_DO, ST_OMP_END_MASTER, ST_OMP_END_ORDERED, ST_OMP_END_PARALLEL,
- ST_OMP_END_PARALLEL_DO, ST_OMP_END_PARALLEL_SECTIONS,
+ ST_OMP_ATOMIC, ST_OMP_BARRIER, ST_OMP_CRITICAL, ST_OMP_END_ATOMIC,
+ ST_OMP_END_CRITICAL, ST_OMP_END_DO, ST_OMP_END_MASTER, ST_OMP_END_ORDERED,
+ ST_OMP_END_PARALLEL, ST_OMP_END_PARALLEL_DO, ST_OMP_END_PARALLEL_SECTIONS,
ST_OMP_END_PARALLEL_WORKSHARE, ST_OMP_END_SECTIONS, ST_OMP_END_SINGLE,
ST_OMP_END_WORKSHARE, ST_OMP_DO, ST_OMP_FLUSH, ST_OMP_MASTER, ST_OMP_ORDERED,
ST_OMP_PARALLEL, ST_OMP_PARALLEL_DO, ST_OMP_PARALLEL_SECTIONS,
ST_OMP_PARALLEL_WORKSHARE, ST_OMP_SECTIONS, ST_OMP_SECTION, ST_OMP_SINGLE,
ST_OMP_THREADPRIVATE, ST_OMP_WORKSHARE, ST_OMP_TASK, ST_OMP_END_TASK,
- ST_OMP_TASKWAIT, ST_PROCEDURE, ST_GENERIC, ST_CRITICAL, ST_END_CRITICAL,
- ST_GET_FCN_CHARACTERISTICS, ST_LOCK, ST_UNLOCK, ST_NONE
+ ST_OMP_TASKWAIT, ST_OMP_TASKYIELD, ST_PROCEDURE, ST_GENERIC, ST_CRITICAL,
+ ST_END_CRITICAL, ST_GET_FCN_CHARACTERISTICS, ST_LOCK, ST_UNLOCK, ST_NONE
}
gfc_statement;
typedef struct gfc_omp_clauses
{
struct gfc_expr *if_expr;
+ struct gfc_expr *final_expr;
struct gfc_expr *num_threads;
gfc_namelist *lists[OMP_LIST_NUM];
enum gfc_omp_sched_kind sched_kind;
struct gfc_expr *chunk_size;
enum gfc_omp_default_sharing default_sharing;
int collapse;
- bool nowait, ordered, untied;
+ bool nowait, ordered, untied, mergeable;
}
gfc_omp_clauses;
EXEC_OMP_PARALLEL_SECTIONS, EXEC_OMP_PARALLEL_WORKSHARE,
EXEC_OMP_SECTIONS, EXEC_OMP_SINGLE, EXEC_OMP_WORKSHARE,
EXEC_OMP_ATOMIC, EXEC_OMP_BARRIER, EXEC_OMP_END_NOWAIT,
- EXEC_OMP_END_SINGLE, EXEC_OMP_TASK, EXEC_OMP_TASKWAIT
+ EXEC_OMP_END_SINGLE, EXEC_OMP_TASK, EXEC_OMP_TASKWAIT,
+ EXEC_OMP_TASKYIELD
}
gfc_exec_op;
+typedef enum
+{
+ GFC_OMP_ATOMIC_UPDATE,
+ GFC_OMP_ATOMIC_READ,
+ GFC_OMP_ATOMIC_WRITE,
+ GFC_OMP_ATOMIC_CAPTURE
+}
+gfc_omp_atomic_op;
+
typedef struct gfc_code
{
gfc_exec_op op;
const char *omp_name;
gfc_namelist *omp_namelist;
bool omp_bool;
+ gfc_omp_atomic_op omp_atomic;
}
ext; /* Points to additional structures required by statement */
@ref{Fortran 2008 status} sections of the documentation.
Additionally, the GNU Fortran compilers supports the OpenMP specification
-(version 3.0, @url{http://openmp.org/@/wp/@/openmp-specifications/}).
+(version 3.1, @url{http://openmp.org/@/wp/@/openmp-specifications/}).
@node Varying Length Character Strings
@subsection Varying Length Character Strings
and environment variables that influence run-time behavior.
GNU Fortran strives to be compatible to the
-@uref{http://www.openmp.org/mp-documents/spec30.pdf,
-OpenMP Application Program Interface v3.0}.
+@uref{http://www.openmp.org/mp-documents/spec31.pdf,
+OpenMP Application Program Interface v3.1}.
To enable the processing of the OpenMP directive @code{!$omp} in
free-form source code; the @code{c$omp}, @code{*$omp} and @code{!$omp}
@section OpenMP Modules @code{OMP_LIB} and @code{OMP_LIB_KINDS}
@table @asis
@item @emph{Standard}:
-OpenMP Application Program Interface v3.0
+OpenMP Application Program Interface v3.1
@end table
below.
For details refer to the actual
-@uref{http://www.openmp.org/mp-documents/spec30.pdf,
-OpenMP Application Program Interface v3.0}.
+@uref{http://www.openmp.org/mp-documents/spec31.pdf,
+OpenMP Application Program Interface v3.1}.
@code{OMP_LIB_KINDS} provides the following scalar default-integer
named constants:
@table @asis
-@item @code{omp_integer_kind}
-@item @code{omp_logical_kind}
@item @code{omp_lock_kind}
@item @code{omp_nest_lock_kind}
@item @code{omp_sched_kind}
@code{OMP_LIB} provides the scalar default-integer
named constant @code{openmp_version} with a value of the form
@var{yyyymm}, where @code{yyyy} is the year and @var{mm} the month
-of the OpenMP version; for OpenMP v3.0 the value is @code{200805}.
+of the OpenMP version; for OpenMP v3.1 the value is @code{201107}.
And the following scalar integer named constants of the
kind @code{omp_sched_kind}:
match gfc_match_omp_single (void);
match gfc_match_omp_task (void);
match gfc_match_omp_taskwait (void);
+match gfc_match_omp_taskyield (void);
match gfc_match_omp_threadprivate (void);
match gfc_match_omp_workshare (void);
match gfc_match_omp_end_nowait (void);
/* OpenMP directive matching and resolving.
- Copyright (C) 2005, 2006, 2007, 2008, 2010
+ Copyright (C) 2005, 2006, 2007, 2008, 2010, 2011
Free Software Foundation, Inc.
Contributed by Jakub Jelinek
return;
gfc_free_expr (c->if_expr);
+ gfc_free_expr (c->final_expr);
gfc_free_expr (c->num_threads);
gfc_free_expr (c->chunk_size);
for (i = 0; i < OMP_LIST_NUM; i++)
#define OMP_CLAUSE_ORDERED (1 << 11)
#define OMP_CLAUSE_COLLAPSE (1 << 12)
#define OMP_CLAUSE_UNTIED (1 << 13)
+#define OMP_CLAUSE_FINAL (1 << 14)
+#define OMP_CLAUSE_MERGEABLE (1 << 15)
/* Match OpenMP directive clauses. MASK is a bitmask of
clauses that are allowed for a particular directive. */
if ((mask & OMP_CLAUSE_IF) && c->if_expr == NULL
&& gfc_match ("if ( %e )", &c->if_expr) == MATCH_YES)
continue;
+ if ((mask & OMP_CLAUSE_FINAL) && c->final_expr == NULL
+ && gfc_match ("final ( %e )", &c->final_expr) == MATCH_YES)
+ continue;
if ((mask & OMP_CLAUSE_NUM_THREADS) && c->num_threads == NULL
&& gfc_match ("num_threads ( %e )", &c->num_threads) == MATCH_YES)
continue;
c->untied = needs_space = true;
continue;
}
+ if ((mask & OMP_CLAUSE_MERGEABLE) && !c->mergeable
+ && gfc_match ("mergeable") == MATCH_YES)
+ {
+ c->mergeable = needs_space = true;
+ continue;
+ }
if ((mask & OMP_CLAUSE_COLLAPSE) && !c->collapse)
{
gfc_expr *cexpr = NULL;
| OMP_CLAUSE_LASTPRIVATE | OMP_CLAUSE_REDUCTION)
#define OMP_TASK_CLAUSES \
(OMP_CLAUSE_PRIVATE | OMP_CLAUSE_FIRSTPRIVATE | OMP_CLAUSE_SHARED \
- | OMP_CLAUSE_IF | OMP_CLAUSE_DEFAULT | OMP_CLAUSE_UNTIED)
+ | OMP_CLAUSE_IF | OMP_CLAUSE_DEFAULT | OMP_CLAUSE_UNTIED \
+ | OMP_CLAUSE_FINAL | OMP_CLAUSE_MERGEABLE)
match
gfc_match_omp_parallel (void)
match
+gfc_match_omp_taskyield (void)
+{
+ if (gfc_match_omp_eos () != MATCH_YES)
+ {
+ gfc_error ("Unexpected junk after TASKYIELD clause at %C");
+ return MATCH_ERROR;
+ }
+ new_st.op = EXEC_OMP_TASKYIELD;
+ new_st.ext.omp_clauses = NULL;
+ return MATCH_YES;
+}
+
+
+match
gfc_match_omp_critical (void)
{
char n[GFC_MAX_SYMBOL_LEN+1];
match
gfc_match_omp_atomic (void)
{
+ gfc_omp_atomic_op op = GFC_OMP_ATOMIC_UPDATE;
+ if (gfc_match ("% update") == MATCH_YES)
+ op = GFC_OMP_ATOMIC_UPDATE;
+ else if (gfc_match ("% read") == MATCH_YES)
+ op = GFC_OMP_ATOMIC_READ;
+ else if (gfc_match ("% write") == MATCH_YES)
+ op = GFC_OMP_ATOMIC_WRITE;
+ else if (gfc_match ("% capture") == MATCH_YES)
+ op = GFC_OMP_ATOMIC_CAPTURE;
if (gfc_match_omp_eos () != MATCH_YES)
{
gfc_error ("Unexpected junk after $OMP ATOMIC statement at %C");
return MATCH_ERROR;
}
new_st.op = EXEC_OMP_ATOMIC;
- new_st.ext.omp_clauses = NULL;
+ new_st.ext.omp_atomic = op;
return MATCH_YES;
}
gfc_error ("IF clause at %L requires a scalar LOGICAL expression",
&expr->where);
}
+ if (omp_clauses->final_expr)
+ {
+ gfc_expr *expr = omp_clauses->final_expr;
+ if (gfc_resolve_expr (expr) == FAILURE
+ || expr->ts.type != BT_LOGICAL || expr->rank != 0)
+ gfc_error ("FINAL clause at %L requires a scalar LOGICAL expression",
+ &expr->where);
+ }
if (omp_clauses->num_threads)
{
gfc_expr *expr = omp_clauses->num_threads;
n->sym->name, name, &code->loc);
if (list != OMP_LIST_PRIVATE)
{
- if (n->sym->attr.pointer)
+ if (n->sym->attr.pointer
+ && list >= OMP_LIST_REDUCTION_FIRST
+ && list <= OMP_LIST_REDUCTION_LAST)
gfc_error ("POINTER object '%s' in %s clause at %L",
n->sym->name, name, &code->loc);
/* Variables in REDUCTION-clauses must be of intrinsic type (flagged below). */
- if ((list < OMP_LIST_REDUCTION_FIRST || list > OMP_LIST_REDUCTION_LAST) &&
- n->sym->ts.type == BT_DERIVED && n->sym->ts.u.derived->attr.alloc_comp)
+ if ((list < OMP_LIST_REDUCTION_FIRST || list > OMP_LIST_REDUCTION_LAST)
+ && n->sym->ts.type == BT_DERIVED
+ && n->sym->ts.u.derived->attr.alloc_comp)
gfc_error ("%s clause object '%s' has ALLOCATABLE components at %L",
name, n->sym->name, &code->loc);
- if (n->sym->attr.cray_pointer)
+ if (n->sym->attr.cray_pointer
+ && list >= OMP_LIST_REDUCTION_FIRST
+ && list <= OMP_LIST_REDUCTION_LAST)
gfc_error ("Cray pointer '%s' in %s clause at %L",
n->sym->name, name, &code->loc);
}
static void
resolve_omp_atomic (gfc_code *code)
{
+ gfc_code *atomic_code = code;
gfc_symbol *var;
- gfc_expr *expr2;
+ gfc_expr *expr2, *expr2_tmp;
code = code->block->next;
gcc_assert (code->op == EXEC_ASSIGN);
- gcc_assert (code->next == NULL);
+ gcc_assert ((atomic_code->ext.omp_atomic != GFC_OMP_ATOMIC_CAPTURE
+ && code->next == NULL)
+ || (atomic_code->ext.omp_atomic == GFC_OMP_ATOMIC_CAPTURE
+ && code->next != NULL
+ && code->next->op == EXEC_ASSIGN
+ && code->next->next == NULL));
if (code->expr1->expr_type != EXPR_VARIABLE
|| code->expr1->symtree == NULL
var = code->expr1->symtree->n.sym;
expr2 = is_conversion (code->expr2, false);
if (expr2 == NULL)
- expr2 = code->expr2;
+ {
+ if (atomic_code->ext.omp_atomic == GFC_OMP_ATOMIC_READ
+ || atomic_code->ext.omp_atomic == GFC_OMP_ATOMIC_WRITE)
+ expr2 = is_conversion (code->expr2, true);
+ if (expr2 == NULL)
+ expr2 = code->expr2;
+ }
+
+ switch (atomic_code->ext.omp_atomic)
+ {
+ case GFC_OMP_ATOMIC_READ:
+ if (expr2->expr_type != EXPR_VARIABLE
+ || expr2->symtree == NULL
+ || expr2->rank != 0
+ || (expr2->ts.type != BT_INTEGER
+ && expr2->ts.type != BT_REAL
+ && expr2->ts.type != BT_COMPLEX
+ && expr2->ts.type != BT_LOGICAL))
+ gfc_error ("!$OMP ATOMIC READ statement must read from a scalar "
+ "variable of intrinsic type at %L", &expr2->where);
+ return;
+ case GFC_OMP_ATOMIC_WRITE:
+ if (expr2->rank != 0 || expr_references_sym (code->expr2, var, NULL))
+ gfc_error ("expr in !$OMP ATOMIC WRITE assignment var = expr "
+ "must be scalar and cannot reference var at %L",
+ &expr2->where);
+ return;
+ case GFC_OMP_ATOMIC_CAPTURE:
+ expr2_tmp = expr2;
+ if (expr2 == code->expr2)
+ {
+ expr2_tmp = is_conversion (code->expr2, true);
+ if (expr2_tmp == NULL)
+ expr2_tmp = expr2;
+ }
+ if (expr2_tmp->expr_type == EXPR_VARIABLE)
+ {
+ if (expr2_tmp->symtree == NULL
+ || expr2_tmp->rank != 0
+ || (expr2_tmp->ts.type != BT_INTEGER
+ && expr2_tmp->ts.type != BT_REAL
+ && expr2_tmp->ts.type != BT_COMPLEX
+ && expr2_tmp->ts.type != BT_LOGICAL)
+ || expr2_tmp->symtree->n.sym == var)
+ {
+ gfc_error ("!$OMP ATOMIC CAPTURE capture statement must read from "
+ "a scalar variable of intrinsic type at %L",
+ &expr2_tmp->where);
+ return;
+ }
+ var = expr2_tmp->symtree->n.sym;
+ code = code->next;
+ if (code->expr1->expr_type != EXPR_VARIABLE
+ || code->expr1->symtree == NULL
+ || code->expr1->rank != 0
+ || (code->expr1->ts.type != BT_INTEGER
+ && code->expr1->ts.type != BT_REAL
+ && code->expr1->ts.type != BT_COMPLEX
+ && code->expr1->ts.type != BT_LOGICAL))
+ {
+ gfc_error ("!$OMP ATOMIC CAPTURE update statement must set "
+ "a scalar variable of intrinsic type at %L",
+ &code->expr1->where);
+ return;
+ }
+ if (code->expr1->symtree->n.sym != var)
+ {
+ gfc_error ("!$OMP ATOMIC CAPTURE capture statement reads from "
+ "different variable than update statement writes "
+ "into at %L", &code->expr1->where);
+ return;
+ }
+ expr2 = is_conversion (code->expr2, false);
+ if (expr2 == NULL)
+ expr2 = code->expr2;
+ }
+ break;
+ default:
+ break;
+ }
if (expr2->expr_type == EXPR_OP)
{
else
gfc_error ("!$OMP ATOMIC assignment must have an operator or intrinsic "
"on right hand side at %L", &expr2->where);
+
+ if (atomic_code->ext.omp_atomic == GFC_OMP_ATOMIC_CAPTURE && code->next)
+ {
+ code = code->next;
+ if (code->expr1->expr_type != EXPR_VARIABLE
+ || code->expr1->symtree == NULL
+ || code->expr1->rank != 0
+ || (code->expr1->ts.type != BT_INTEGER
+ && code->expr1->ts.type != BT_REAL
+ && code->expr1->ts.type != BT_COMPLEX
+ && code->expr1->ts.type != BT_LOGICAL))
+ {
+ gfc_error ("!$OMP ATOMIC CAPTURE capture statement must set "
+ "a scalar variable of intrinsic type at %L",
+ &code->expr1->where);
+ return;
+ }
+
+ expr2 = is_conversion (code->expr2, false);
+ if (expr2 == NULL)
+ {
+ expr2 = is_conversion (code->expr2, true);
+ if (expr2 == NULL)
+ expr2 = code->expr2;
+ }
+
+ if (expr2->expr_type != EXPR_VARIABLE
+ || expr2->symtree == NULL
+ || expr2->rank != 0
+ || (expr2->ts.type != BT_INTEGER
+ && expr2->ts.type != BT_REAL
+ && expr2->ts.type != BT_COMPLEX
+ && expr2->ts.type != BT_LOGICAL))
+ {
+ gfc_error ("!$OMP ATOMIC CAPTURE capture statement must read "
+ "from a scalar variable of intrinsic type at %L",
+ &expr2->where);
+ return;
+ }
+ if (expr2->symtree->n.sym != var)
+ {
+ gfc_error ("!$OMP ATOMIC CAPTURE capture statement reads from "
+ "different variable than update statement writes "
+ "into at %L", &expr2->where);
+ return;
+ }
+ }
}
match ("do", gfc_match_omp_do, ST_OMP_DO);
break;
case 'e':
+ match ("end atomic", gfc_match_omp_eos, ST_OMP_END_ATOMIC);
match ("end critical", gfc_match_omp_critical, ST_OMP_END_CRITICAL);
match ("end do", gfc_match_omp_end_nowait, ST_OMP_END_DO);
match ("end master", gfc_match_omp_eos, ST_OMP_END_MASTER);
case 't':
match ("task", gfc_match_omp_task, ST_OMP_TASK);
match ("taskwait", gfc_match_omp_taskwait, ST_OMP_TASKWAIT);
+ match ("taskyield", gfc_match_omp_taskyield, ST_OMP_TASKYIELD);
match ("threadprivate", gfc_match_omp_threadprivate,
ST_OMP_THREADPRIVATE);
case 'w':
case ST_POINTER_ASSIGNMENT: case ST_EXIT: case ST_CYCLE: \
case ST_ASSIGNMENT: case ST_ARITHMETIC_IF: case ST_WHERE: case ST_FORALL: \
case ST_LABEL_ASSIGNMENT: case ST_FLUSH: case ST_OMP_FLUSH: \
- case ST_OMP_BARRIER: case ST_OMP_TASKWAIT: case ST_ERROR_STOP: \
- case ST_SYNC_ALL: case ST_SYNC_IMAGES: case ST_SYNC_MEMORY: \
- case ST_LOCK: case ST_UNLOCK
+ case ST_OMP_BARRIER: case ST_OMP_TASKWAIT: case ST_OMP_TASKYIELD: \
+ case ST_ERROR_STOP: case ST_SYNC_ALL: case ST_SYNC_IMAGES: \
+ case ST_SYNC_MEMORY: case ST_LOCK: case ST_UNLOCK
/* Statements that mark other executable statements. */
case ST_OMP_DO:
p = "!$OMP DO";
break;
+ case ST_OMP_END_ATOMIC:
+ p = "!$OMP END ATOMIC";
+ break;
case ST_OMP_END_CRITICAL:
p = "!$OMP END CRITICAL";
break;
case ST_OMP_TASKWAIT:
p = "!$OMP TASKWAIT";
break;
+ case ST_OMP_TASKYIELD:
+ p = "!$OMP TASKYIELD";
+ break;
case ST_OMP_THREADPRIVATE:
p = "!$OMP THREADPRIVATE";
break;
/* Parse the statements of OpenMP atomic directive. */
-static void
+static gfc_statement
parse_omp_atomic (void)
{
gfc_statement st;
gfc_code *cp, *np;
gfc_state_data s;
+ int count;
accept_statement (ST_OMP_ATOMIC);
np = new_level (cp);
np->op = cp->op;
np->block = NULL;
+ count = 1 + (cp->ext.omp_atomic == GFC_OMP_ATOMIC_CAPTURE);
- for (;;)
+ while (count)
{
st = next_statement ();
if (st == ST_NONE)
unexpected_eof ();
else if (st == ST_ASSIGNMENT)
- break;
+ {
+ accept_statement (st);
+ count--;
+ }
else
unexpected_statement (st);
}
- accept_statement (st);
-
pop_state ();
+
+ st = next_statement ();
+ if (st == ST_OMP_END_ATOMIC)
+ {
+ gfc_clear_new_st ();
+ gfc_commit_symbols ();
+ gfc_warning_check ();
+ st = next_statement ();
+ }
+ else if (cp->ext.omp_atomic == GFC_OMP_ATOMIC_CAPTURE)
+ gfc_error ("Missing !$OMP END ATOMIC after !$OMP ATOMIC CAPTURE at %C");
+ return st;
}
continue;
case ST_OMP_ATOMIC:
- parse_omp_atomic ();
- break;
+ st = parse_omp_atomic ();
+ continue;
default:
cycle = false;
continue;
case ST_OMP_ATOMIC:
- parse_omp_atomic ();
- break;
+ st = parse_omp_atomic ();
+ continue;
default:
return st;
case EXEC_OMP_SINGLE:
case EXEC_OMP_TASK:
case EXEC_OMP_TASKWAIT:
+ case EXEC_OMP_TASKYIELD:
case EXEC_OMP_WORKSHARE:
break;
case EXEC_OMP_SECTIONS:
case EXEC_OMP_SINGLE:
case EXEC_OMP_TASKWAIT:
+ case EXEC_OMP_TASKYIELD:
case EXEC_OMP_WORKSHARE:
gfc_resolve_omp_directive (code, ns);
break;
case EXEC_OMP_ORDERED:
case EXEC_OMP_END_NOWAIT:
case EXEC_OMP_TASKWAIT:
+ case EXEC_OMP_TASKYIELD:
break;
default:
if (GFC_DECL_CRAY_POINTEE (decl))
return OMP_CLAUSE_DEFAULT_PRIVATE;
- /* Assumed-size arrays are predetermined to inherit sharing
- attributes of the associated actual argument, which is shared
- for all we care. */
+ /* Assumed-size arrays are predetermined shared. */
if (TREE_CODE (decl) == PARM_DECL
&& GFC_ARRAY_TYPE_P (TREE_TYPE (decl))
&& GFC_TYPE_ARRAY_AKIND (TREE_TYPE (decl)) == GFC_ARRAY_UNKNOWN
gfc_omp_clause_copy_ctor (tree clause, tree dest, tree src)
{
tree type = TREE_TYPE (dest), ptr, size, esize, rank, call;
- stmtblock_t block;
+ tree cond, then_b, else_b;
+ stmtblock_t block, cond_block;
if (! GFC_DESCRIPTOR_TYPE_P (type)
|| GFC_TYPE_ARRAY_AKIND (type) != GFC_ARRAY_ALLOCATABLE)
and copied from SRC. */
gfc_start_block (&block);
- gfc_add_modify (&block, dest, src);
+ gfc_init_block (&cond_block);
+
+ gfc_add_modify (&cond_block, dest, src);
rank = gfc_rank_cst[GFC_TYPE_ARRAY_RANK (type) - 1];
size = gfc_conv_descriptor_ubound_get (dest, rank);
size = fold_build2_loc (input_location, MINUS_EXPR, gfc_array_index_type,
TYPE_SIZE_UNIT (gfc_get_element_type (type)));
size = fold_build2_loc (input_location, MULT_EXPR, gfc_array_index_type,
size, esize);
- size = gfc_evaluate_now (fold_convert (size_type_node, size), &block);
+ size = gfc_evaluate_now (fold_convert (size_type_node, size), &cond_block);
ptr = gfc_create_var (pvoid_type_node, NULL);
- gfc_allocate_using_malloc (&block, ptr, size, NULL_TREE);
- gfc_conv_descriptor_data_set (&block, dest, ptr);
+ gfc_allocate_using_malloc (&cond_block, ptr, size, NULL_TREE);
+ gfc_conv_descriptor_data_set (&cond_block, dest, ptr);
call = build_call_expr_loc (input_location,
built_in_decls[BUILT_IN_MEMCPY], 3, ptr,
fold_convert (pvoid_type_node,
gfc_conv_descriptor_data_get (src)),
size);
- gfc_add_expr_to_block (&block, fold_convert (void_type_node, call));
+ gfc_add_expr_to_block (&cond_block, fold_convert (void_type_node, call));
+ then_b = gfc_finish_block (&cond_block);
+
+ gfc_init_block (&cond_block);
+ gfc_conv_descriptor_data_set (&cond_block, dest, null_pointer_node);
+ else_b = gfc_finish_block (&cond_block);
+
+ cond = fold_build2_loc (input_location, NE_EXPR, boolean_type_node,
+ fold_convert (pvoid_type_node,
+ gfc_conv_descriptor_data_get (src)),
+ null_pointer_node);
+ gfc_add_expr_to_block (&block, build3_loc (input_location, COND_EXPR,
+ void_type_node, cond, then_b, else_b));
return gfc_finish_block (&block);
}
omp_clauses = gfc_trans_add_clause (c, omp_clauses);
}
+ if (clauses->final_expr)
+ {
+ tree final_var;
+
+ gfc_init_se (&se, NULL);
+ gfc_conv_expr (&se, clauses->final_expr);
+ gfc_add_block_to_block (block, &se.pre);
+ final_var = gfc_evaluate_now (se.expr, block);
+ gfc_add_block_to_block (block, &se.post);
+
+ c = build_omp_clause (where.lb->location, OMP_CLAUSE_FINAL);
+ OMP_CLAUSE_FINAL_EXPR (c) = final_var;
+ omp_clauses = gfc_trans_add_clause (c, omp_clauses);
+ }
+
if (clauses->num_threads)
{
tree num_threads;
omp_clauses = gfc_trans_add_clause (c, omp_clauses);
}
+ if (clauses->mergeable)
+ {
+ c = build_omp_clause (where.lb->location, OMP_CLAUSE_MERGEABLE);
+ omp_clauses = gfc_trans_add_clause (c, omp_clauses);
+ }
+
if (clauses->collapse)
{
c = build_omp_clause (where.lb->location, OMP_CLAUSE_COLLAPSE);
static tree
gfc_trans_omp_atomic (gfc_code *code)
{
+ gfc_code *atomic_code = code;
gfc_se lse;
gfc_se rse;
+ gfc_se vse;
gfc_expr *expr2, *e;
gfc_symbol *var;
stmtblock_t block;
tree lhsaddr, type, rhs, x;
enum tree_code op = ERROR_MARK;
+ enum tree_code aop = OMP_ATOMIC;
bool var_on_left = false;
code = code->block->next;
gcc_assert (code->op == EXEC_ASSIGN);
- gcc_assert (code->next == NULL);
var = code->expr1->symtree->n.sym;
gfc_init_se (&lse, NULL);
gfc_init_se (&rse, NULL);
+ gfc_init_se (&vse, NULL);
gfc_start_block (&block);
- gfc_conv_expr (&lse, code->expr1);
- gfc_add_block_to_block (&block, &lse.pre);
- type = TREE_TYPE (lse.expr);
- lhsaddr = gfc_build_addr_expr (NULL, lse.expr);
-
expr2 = code->expr2;
if (expr2->expr_type == EXPR_FUNCTION
&& expr2->value.function.isym->id == GFC_ISYM_CONVERSION)
expr2 = expr2->value.function.actual->expr;
- if (expr2->expr_type == EXPR_OP)
+ switch (atomic_code->ext.omp_atomic)
+ {
+ case GFC_OMP_ATOMIC_READ:
+ gfc_conv_expr (&vse, code->expr1);
+ gfc_add_block_to_block (&block, &vse.pre);
+
+ gfc_conv_expr (&lse, expr2);
+ gfc_add_block_to_block (&block, &lse.pre);
+ type = TREE_TYPE (lse.expr);
+ lhsaddr = gfc_build_addr_expr (NULL, lse.expr);
+
+ x = build1 (OMP_ATOMIC_READ, type, lhsaddr);
+ x = convert (TREE_TYPE (vse.expr), x);
+ gfc_add_modify (&block, vse.expr, x);
+
+ gfc_add_block_to_block (&block, &lse.pre);
+ gfc_add_block_to_block (&block, &rse.pre);
+
+ return gfc_finish_block (&block);
+ case GFC_OMP_ATOMIC_CAPTURE:
+ aop = OMP_ATOMIC_CAPTURE_NEW;
+ if (expr2->expr_type == EXPR_VARIABLE)
+ {
+ aop = OMP_ATOMIC_CAPTURE_OLD;
+ gfc_conv_expr (&vse, code->expr1);
+ gfc_add_block_to_block (&block, &vse.pre);
+
+ gfc_conv_expr (&lse, expr2);
+ gfc_add_block_to_block (&block, &lse.pre);
+ gfc_init_se (&lse, NULL);
+ code = code->next;
+ var = code->expr1->symtree->n.sym;
+ expr2 = code->expr2;
+ if (expr2->expr_type == EXPR_FUNCTION
+ && expr2->value.function.isym->id == GFC_ISYM_CONVERSION)
+ expr2 = expr2->value.function.actual->expr;
+ }
+ break;
+ default:
+ break;
+ }
+
+ gfc_conv_expr (&lse, code->expr1);
+ gfc_add_block_to_block (&block, &lse.pre);
+ type = TREE_TYPE (lse.expr);
+ lhsaddr = gfc_build_addr_expr (NULL, lse.expr);
+
+ if (atomic_code->ext.omp_atomic == GFC_OMP_ATOMIC_WRITE)
+ {
+ gfc_conv_expr (&rse, expr2);
+ gfc_add_block_to_block (&block, &rse.pre);
+ }
+ else if (expr2->expr_type == EXPR_OP)
{
gfc_expr *e;
switch (expr2->value.op.op)
lhsaddr = save_expr (lhsaddr);
rhs = gfc_evaluate_now (rse.expr, &block);
- x = convert (TREE_TYPE (rhs), build_fold_indirect_ref_loc (input_location,
- lhsaddr));
- if (var_on_left)
- x = fold_build2_loc (input_location, op, TREE_TYPE (rhs), x, rhs);
+ if (atomic_code->ext.omp_atomic == GFC_OMP_ATOMIC_WRITE)
+ x = rhs;
else
- x = fold_build2_loc (input_location, op, TREE_TYPE (rhs), rhs, x);
+ {
+ x = convert (TREE_TYPE (rhs),
+ build_fold_indirect_ref_loc (input_location, lhsaddr));
+ if (var_on_left)
+ x = fold_build2_loc (input_location, op, TREE_TYPE (rhs), x, rhs);
+ else
+ x = fold_build2_loc (input_location, op, TREE_TYPE (rhs), rhs, x);
+ }
if (TREE_CODE (TREE_TYPE (rhs)) == COMPLEX_TYPE
&& TREE_CODE (type) != COMPLEX_TYPE)
x = fold_build1_loc (input_location, REALPART_EXPR,
TREE_TYPE (TREE_TYPE (rhs)), x);
- x = build2_v (OMP_ATOMIC, lhsaddr, convert (type, x));
- gfc_add_expr_to_block (&block, x);
-
gfc_add_block_to_block (&block, &lse.pre);
gfc_add_block_to_block (&block, &rse.pre);
+ if (aop == OMP_ATOMIC)
+ {
+ x = build2_v (OMP_ATOMIC, lhsaddr, convert (type, x));
+ gfc_add_expr_to_block (&block, x);
+ }
+ else
+ {
+ if (aop == OMP_ATOMIC_CAPTURE_NEW)
+ {
+ code = code->next;
+ expr2 = code->expr2;
+ if (expr2->expr_type == EXPR_FUNCTION
+ && expr2->value.function.isym->id == GFC_ISYM_CONVERSION)
+ expr2 = expr2->value.function.actual->expr;
+
+ gcc_assert (expr2->expr_type == EXPR_VARIABLE);
+ gfc_conv_expr (&vse, code->expr1);
+ gfc_add_block_to_block (&block, &vse.pre);
+
+ gfc_init_se (&lse, NULL);
+ gfc_conv_expr (&lse, expr2);
+ gfc_add_block_to_block (&block, &lse.pre);
+ }
+ x = build2 (aop, type, lhsaddr, convert (type, x));
+ x = convert (TREE_TYPE (vse.expr), x);
+ gfc_add_modify (&block, vse.expr, x);
+ }
+
return gfc_finish_block (&block);
}
}
static tree
+gfc_trans_omp_taskyield (void)
+{
+ tree decl = built_in_decls [BUILT_IN_GOMP_TASKYIELD];
+ return build_call_expr_loc (input_location, decl, 0);
+}
+
+static tree
gfc_trans_omp_workshare (gfc_code *code, gfc_omp_clauses *clauses)
{
tree res, tmp, stmt;
return gfc_trans_omp_task (code);
case EXEC_OMP_TASKWAIT:
return gfc_trans_omp_taskwait ();
+ case EXEC_OMP_TASKYIELD:
+ return gfc_trans_omp_taskyield ();
case EXEC_OMP_WORKSHARE:
return gfc_trans_omp_workshare (code, code->ext.omp_clauses);
default:
case EXEC_OMP_SINGLE:
case EXEC_OMP_TASK:
case EXEC_OMP_TASKWAIT:
+ case EXEC_OMP_TASKYIELD:
case EXEC_OMP_WORKSHARE:
res = gfc_trans_omp_directive (code);
break;
GF_OMP_RETURN_NOWAIT = 1 << 0,
GF_OMP_SECTION_LAST = 1 << 0,
+ GF_OMP_ATOMIC_NEED_VALUE = 1 << 0,
GF_PREDICT_TAKEN = 1 << 15
};
}
+/* Return true if OMP atomic load/store statement G has the
+ GF_OMP_ATOMIC_NEED_VALUE flag set. */
+
+static inline bool
+gimple_omp_atomic_need_value_p (const_gimple g)
+{
+ if (gimple_code (g) != GIMPLE_OMP_ATOMIC_LOAD)
+ GIMPLE_CHECK (g, GIMPLE_OMP_ATOMIC_STORE);
+ return (gimple_omp_subcode (g) & GF_OMP_ATOMIC_NEED_VALUE) != 0;
+}
+
+
+/* Set the GF_OMP_ATOMIC_NEED_VALUE flag on G. */
+
+static inline void
+gimple_omp_atomic_set_need_value (gimple g)
+{
+ if (gimple_code (g) != GIMPLE_OMP_ATOMIC_LOAD)
+ GIMPLE_CHECK (g, GIMPLE_OMP_ATOMIC_STORE);
+ g->gsbase.subcode |= GF_OMP_ATOMIC_NEED_VALUE;
+}
+
+
/* Return the number of operands for statement GS. */
static inline unsigned
}
break;
+ case OMP_CLAUSE_FINAL:
case OMP_CLAUSE_IF:
OMP_CLAUSE_OPERAND (c, 0)
= gimple_boolify (OMP_CLAUSE_OPERAND (c, 0));
case OMP_CLAUSE_ORDERED:
case OMP_CLAUSE_UNTIED:
case OMP_CLAUSE_COLLAPSE:
+ case OMP_CLAUSE_MERGEABLE:
break;
case OMP_CLAUSE_DEFAULT:
case OMP_CLAUSE_DEFAULT:
case OMP_CLAUSE_UNTIED:
case OMP_CLAUSE_COLLAPSE:
+ case OMP_CLAUSE_FINAL:
+ case OMP_CLAUSE_MERGEABLE:
break;
default:
gimplify_omp_atomic (tree *expr_p, gimple_seq *pre_p)
{
tree addr = TREE_OPERAND (*expr_p, 0);
- tree rhs = TREE_OPERAND (*expr_p, 1);
+ tree rhs = TREE_CODE (*expr_p) == OMP_ATOMIC_READ
+ ? NULL : TREE_OPERAND (*expr_p, 1);
tree type = TYPE_MAIN_VARIANT (TREE_TYPE (TREE_TYPE (addr)));
tree tmp_load;
+ gimple loadstmt, storestmt;
- tmp_load = create_tmp_reg (type, NULL);
- if (goa_stabilize_expr (&rhs, pre_p, addr, tmp_load) < 0)
- return GS_ERROR;
+ tmp_load = create_tmp_reg (type, NULL);
+ if (rhs && goa_stabilize_expr (&rhs, pre_p, addr, tmp_load) < 0)
+ return GS_ERROR;
+
+ if (gimplify_expr (&addr, pre_p, NULL, is_gimple_val, fb_rvalue)
+ != GS_ALL_DONE)
+ return GS_ERROR;
- if (gimplify_expr (&addr, pre_p, NULL, is_gimple_val, fb_rvalue)
- != GS_ALL_DONE)
- return GS_ERROR;
+ loadstmt = gimple_build_omp_atomic_load (tmp_load, addr);
+ gimplify_seq_add_stmt (pre_p, loadstmt);
+ if (rhs && gimplify_expr (&rhs, pre_p, NULL, is_gimple_val, fb_rvalue)
+ != GS_ALL_DONE)
+ return GS_ERROR;
- gimplify_seq_add_stmt (pre_p, gimple_build_omp_atomic_load (tmp_load, addr));
- if (gimplify_expr (&rhs, pre_p, NULL, is_gimple_val, fb_rvalue)
- != GS_ALL_DONE)
- return GS_ERROR;
- gimplify_seq_add_stmt (pre_p, gimple_build_omp_atomic_store (rhs));
- *expr_p = NULL;
+ if (TREE_CODE (*expr_p) == OMP_ATOMIC_READ)
+ rhs = tmp_load;
+ storestmt = gimple_build_omp_atomic_store (rhs);
+ gimplify_seq_add_stmt (pre_p, storestmt);
+ switch (TREE_CODE (*expr_p))
+ {
+ case OMP_ATOMIC_READ:
+ case OMP_ATOMIC_CAPTURE_OLD:
+ *expr_p = tmp_load;
+ gimple_omp_atomic_set_need_value (loadstmt);
+ break;
+ case OMP_ATOMIC_CAPTURE_NEW:
+ *expr_p = rhs;
+ gimple_omp_atomic_set_need_value (storestmt);
+ break;
+ default:
+ *expr_p = NULL;
+ break;
+ }
return GS_ALL_DONE;
}
}
case OMP_ATOMIC:
+ case OMP_ATOMIC_READ:
+ case OMP_ATOMIC_CAPTURE_OLD:
+ case OMP_ATOMIC_CAPTURE_NEW:
ret = gimplify_omp_atomic (expr_p, pre_p);
break;
BT_FN_VOID, ATTR_NOTHROW_LEAF_LIST)
DEF_GOMP_BUILTIN (BUILT_IN_GOMP_TASKWAIT, "GOMP_taskwait",
BT_FN_VOID, ATTR_NOTHROW_LEAF_LIST)
+DEF_GOMP_BUILTIN (BUILT_IN_GOMP_TASKYIELD, "GOMP_taskyield",
+ BT_FN_VOID, ATTR_NOTHROW_LEAF_LIST)
DEF_GOMP_BUILTIN (BUILT_IN_GOMP_CRITICAL_START, "GOMP_critical_start",
BT_FN_VOID, ATTR_NOTHROW_LEAF_LIST)
DEF_GOMP_BUILTIN (BUILT_IN_GOMP_CRITICAL_END, "GOMP_critical_end",
ctx->default_kind = OMP_CLAUSE_DEFAULT_KIND (c);
break;
+ case OMP_CLAUSE_FINAL:
case OMP_CLAUSE_IF:
case OMP_CLAUSE_NUM_THREADS:
case OMP_CLAUSE_SCHEDULE:
case OMP_CLAUSE_ORDERED:
case OMP_CLAUSE_COLLAPSE:
case OMP_CLAUSE_UNTIED:
+ case OMP_CLAUSE_MERGEABLE:
break;
default:
case OMP_CLAUSE_ORDERED:
case OMP_CLAUSE_COLLAPSE:
case OMP_CLAUSE_UNTIED:
+ case OMP_CLAUSE_FINAL:
+ case OMP_CLAUSE_MERGEABLE:
break;
default:
static void
expand_task_call (basic_block bb, gimple entry_stmt)
{
- tree t, t1, t2, t3, flags, cond, c, clauses;
+ tree t, t1, t2, t3, flags, cond, c, c2, clauses;
gimple_stmt_iterator gsi;
location_t loc = gimple_location (entry_stmt);
cond = boolean_true_node;
c = find_omp_clause (clauses, OMP_CLAUSE_UNTIED);
- flags = build_int_cst (unsigned_type_node, (c ? 1 : 0));
+ c2 = find_omp_clause (clauses, OMP_CLAUSE_MERGEABLE);
+ flags = build_int_cst (unsigned_type_node,
+ (c ? 1 : 0) + (c2 ? 4 : 0));
+
+ c = find_omp_clause (clauses, OMP_CLAUSE_FINAL);
+ if (c)
+ {
+ c = gimple_boolify (OMP_CLAUSE_FINAL_EXPR (c));
+ c = fold_build3_loc (loc, COND_EXPR, unsigned_type_node, c,
+ build_int_cst (unsigned_type_node, 2),
+ build_int_cst (unsigned_type_node, 0));
+ flags = fold_build2_loc (loc, PLUS_EXPR, unsigned_type_node, flags, c);
+ }
gsi = gsi_last_bb (bb);
t = gimple_omp_task_data_arg (entry_stmt);
}
/* A subroutine of expand_omp_atomic. Attempt to implement the atomic
+ operation as a normal volatile load. */
+
+static bool
+expand_omp_atomic_load (basic_block load_bb, tree addr, tree loaded_val)
+{
+ /* FIXME */
+ (void) load_bb;
+ (void) addr;
+ (void) loaded_val;
+ return false;
+}
+
+/* A subroutine of expand_omp_atomic. Attempt to implement the atomic
+ operation as a normal volatile store. */
+
+static bool
+expand_omp_atomic_store (basic_block load_bb, tree addr)
+{
+ /* FIXME */
+ (void) load_bb;
+ (void) addr;
+ return false;
+}
+
+/* A subroutine of expand_omp_atomic. Attempt to implement the atomic
operation as a __sync_fetch_and_op builtin. INDEX is log2 of the
size of the data type, and thus usable to find the index of the builtin
decl. Returns false if the expression is not of the proper form. */
tree addr, tree loaded_val,
tree stored_val, int index)
{
- enum built_in_function base;
+ enum built_in_function oldbase, newbase;
tree decl, itype, call;
- direct_optab optab;
- tree rhs;
+ direct_optab optab, oldoptab, newoptab;
+ tree lhs, rhs;
basic_block store_bb = single_succ (load_bb);
gimple_stmt_iterator gsi;
gimple stmt;
location_t loc;
+ bool need_old, need_new;
/* We expect to find the following sequences:
gsi_next (&gsi);
if (gimple_code (gsi_stmt (gsi)) != GIMPLE_OMP_ATOMIC_STORE)
return false;
+ need_new = gimple_omp_atomic_need_value_p (gsi_stmt (gsi));
+ need_old = gimple_omp_atomic_need_value_p (last_stmt (load_bb));
+ gcc_checking_assert (!need_old || !need_new);
if (!operand_equal_p (gimple_assign_lhs (stmt), stored_val, 0))
return false;
{
case PLUS_EXPR:
case POINTER_PLUS_EXPR:
- base = BUILT_IN_SYNC_FETCH_AND_ADD_N;
+ oldbase = BUILT_IN_SYNC_FETCH_AND_ADD_N;
+ newbase = BUILT_IN_SYNC_ADD_AND_FETCH_N;
optab = sync_add_optab;
+ oldoptab = sync_old_add_optab;
+ newoptab = sync_new_add_optab;
break;
case MINUS_EXPR:
- base = BUILT_IN_SYNC_FETCH_AND_SUB_N;
+ oldbase = BUILT_IN_SYNC_FETCH_AND_SUB_N;
+ newbase = BUILT_IN_SYNC_SUB_AND_FETCH_N;
optab = sync_add_optab;
+ oldoptab = sync_old_add_optab;
+ newoptab = sync_new_add_optab;
break;
case BIT_AND_EXPR:
- base = BUILT_IN_SYNC_FETCH_AND_AND_N;
+ oldbase = BUILT_IN_SYNC_FETCH_AND_AND_N;
+ newbase = BUILT_IN_SYNC_AND_AND_FETCH_N;
optab = sync_and_optab;
+ oldoptab = sync_old_and_optab;
+ newoptab = sync_new_and_optab;
break;
case BIT_IOR_EXPR:
- base = BUILT_IN_SYNC_FETCH_AND_OR_N;
+ oldbase = BUILT_IN_SYNC_FETCH_AND_OR_N;
+ newbase = BUILT_IN_SYNC_OR_AND_FETCH_N;
optab = sync_ior_optab;
+ oldoptab = sync_old_ior_optab;
+ newoptab = sync_new_ior_optab;
break;
case BIT_XOR_EXPR:
- base = BUILT_IN_SYNC_FETCH_AND_XOR_N;
+ oldbase = BUILT_IN_SYNC_FETCH_AND_XOR_N;
+ newbase = BUILT_IN_SYNC_XOR_AND_FETCH_N;
optab = sync_xor_optab;
+ oldoptab = sync_old_xor_optab;
+ newoptab = sync_new_xor_optab;
break;
default:
return false;
else
return false;
- decl = built_in_decls[base + index + 1];
+ decl = built_in_decls[(need_new ? newbase : oldbase) + index + 1];
if (decl == NULL_TREE)
return false;
itype = TREE_TYPE (TREE_TYPE (decl));
- if (direct_optab_handler (optab, TYPE_MODE (itype)) == CODE_FOR_nothing)
+ if (need_new)
+ {
+ /* expand_sync_fetch_operation can always compensate when interested
+ in the new value. */
+ if (direct_optab_handler (newoptab, TYPE_MODE (itype))
+ == CODE_FOR_nothing
+ && direct_optab_handler (oldoptab, TYPE_MODE (itype))
+ == CODE_FOR_nothing)
+ return false;
+ }
+ else if (need_old)
+ {
+ /* When interested in the old value, expand_sync_fetch_operation
+ can compensate only if the operation is reversible. AND and OR
+ are not reversible. */
+ if (direct_optab_handler (oldoptab, TYPE_MODE (itype))
+ == CODE_FOR_nothing
+ && (oldbase == BUILT_IN_SYNC_FETCH_AND_AND_N
+ || oldbase == BUILT_IN_SYNC_FETCH_AND_OR_N
+ || direct_optab_handler (newoptab, TYPE_MODE (itype))
+ == CODE_FOR_nothing))
+ return false;
+ }
+ else if (direct_optab_handler (optab, TYPE_MODE (itype)) == CODE_FOR_nothing)
return false;
gsi = gsi_last_bb (load_bb);
gcc_assert (gimple_code (gsi_stmt (gsi)) == GIMPLE_OMP_ATOMIC_LOAD);
- call = build_call_expr_loc (loc,
- decl, 2, addr,
- fold_convert_loc (loc, itype, rhs));
- call = fold_convert_loc (loc, void_type_node, call);
+ call = build_call_expr_loc (loc, decl, 2, addr,
+ fold_convert_loc (loc, itype, rhs));
+ if (need_old || need_new)
+ {
+ lhs = need_old ? loaded_val : stored_val;
+ call = fold_convert_loc (loc, TREE_TYPE (lhs), call);
+ call = build2_loc (loc, MODIFY_EXPR, void_type_node, lhs, call);
+ }
+ else
+ call = fold_convert_loc (loc, void_type_node, call);
force_gimple_operand_gsi (&gsi, call, true, NULL_TREE, true, GSI_SAME_STMT);
gsi_remove (&gsi, true);
/* __sync builtins require strict data alignment. */
if (exact_log2 (align) >= index)
{
+ /* Atomic load. FIXME: have some target hook signalize what loads
+ are actually atomic? */
+ if (loaded_val == stored_val
+ && (GET_MODE_CLASS (TYPE_MODE (type)) == MODE_INT
+ || GET_MODE_CLASS (TYPE_MODE (type)) == MODE_FLOAT)
+ && GET_MODE_BITSIZE (TYPE_MODE (type)) <= BITS_PER_WORD
+ && expand_omp_atomic_load (load_bb, addr, loaded_val))
+ return;
+
+ /* Atomic store. FIXME: have some target hook signalize what
+ stores are actually atomic? */
+ if ((GET_MODE_CLASS (TYPE_MODE (type)) == MODE_INT
+ || GET_MODE_CLASS (TYPE_MODE (type)) == MODE_FLOAT)
+ && GET_MODE_BITSIZE (TYPE_MODE (type)) <= BITS_PER_WORD
+ && store_bb == single_succ (load_bb)
+ && first_stmt (store_bb) == store
+ && expand_omp_atomic_store (load_bb, addr))
+ return;
+
/* When possible, use specialized atomic update functions. */
if ((INTEGRAL_TYPE_P (type) || POINTER_TYPE_P (type))
&& store_bb == single_succ (load_bb))
+2011-08-02 Jakub Jelinek <jakub@redhat.com>
+
+ PR fortran/46752
+ * gcc.dg/gomp/atomic-5.c: Adjust expected diagnostics.
+ * gcc.dg/gomp/atomic-15.c: New test.
+ * g++.dg/gomp/atomic-5.C: Adjust expected diagnostics.
+ * g++.dg/gomp/atomic-15.C: New test.
+ * g++.dg/gomp/private-1.C: New test.
+ * g++.dg/gomp/sharing-2.C: New test.
+ * gfortran.dg/gomp/crayptr1.f90: Don't expect error
+ about Cray pointer in FIRSTPRIVATE/LASTPRIVATE.
+ * gfortran.dg/gomp/omp_atomic2.f90: New test.
+
2011-08-02 Tobias Burnus <burnus@net-b.de>
* trim_optimize_5.f90: Remove spurious "use foo".
--- /dev/null
+// { dg-do compile }
+// { dg-options "-fopenmp" }
+
+int x = 6;
+
+int
+main ()
+{
+ int v;
+ #pragma omp atomic
+ x = x * 7 + 6; // { dg-error "expected" }
+ #pragma omp atomic
+ x = x * 7 ^ 6; // { dg-error "expected" }
+ #pragma omp atomic update
+ x = x - 8 + 6; // { dg-error "expected" }
+ #pragma omp atomic
+ x = x ^ 7 | 2; // { dg-error "expected" }
+ #pragma omp atomic
+ x = x / 7 * 2; // { dg-error "expected" }
+ #pragma omp atomic
+ x = x / 7 / 2; // { dg-error "expected" }
+ #pragma omp atomic capture
+ v = x = x | 6; // { dg-error "invalid operator" }
+ #pragma omp atomic capture
+ { v = x; x = x * 7 + 6; } // { dg-error "expected" }
+ #pragma omp atomic capture
+ { v = x; x = x * 7 ^ 6; } // { dg-error "expected" }
+ #pragma omp atomic capture
+ { v = x; x = x - 8 + 6; } // { dg-error "expected" }
+ #pragma omp atomic capture
+ { v = x; x = x ^ 7 | 2; } // { dg-error "expected" }
+ #pragma omp atomic capture
+ { v = x; x = x / 7 * 2; } // { dg-error "expected" }
+ #pragma omp atomic capture
+ { v = x; x = x / 7 / 2; } // { dg-error "expected" }
+ #pragma omp atomic capture
+ { x = x * 7 + 6; v = x; } // { dg-error "expected" }
+ #pragma omp atomic capture
+ { x = x * 7 ^ 6; v = x; } // { dg-error "expected" }
+ #pragma omp atomic capture
+ { x = x - 8 + 6; v = x; } // { dg-error "expected" }
+ #pragma omp atomic capture
+ { x = x ^ 7 | 2; v = x; } // { dg-error "expected" }
+ (void) v;
+ return 0;
+}
#pragma omp atomic
x %= 2; /* { dg-error "invalid operator" } */
#pragma omp atomic
- x = x + 1; /* { dg-error "invalid operator" } */
+ x = x + 1;
#pragma omp atomic
- x = 1; /* { dg-error "invalid operator" } */
+ x = 1; /* { dg-error "invalid form" } */
#pragma omp atomic
++y; /* { dg-error "read-only variable" } */
#pragma omp atomic
;
#pragma omp p private (c) // { dg-error "predetermined 'shared'" }
;
-#pragma omp p firstprivate (c) // { dg-error "predetermined 'shared'" }
+#pragma omp p firstprivate (c)
;
#pragma omp p for lastprivate (c) // { dg-error "predetermined 'shared'" }
for (i = 0; i < 10; i++)
--- /dev/null
+// { dg-do compile }
+// { dg-options "-fopenmp" }
+
+struct A { int i; A (); ~A (); };
+struct B { int i; };
+struct C { int i; mutable int j; C (); ~C (); };
+
+template <typename T> void bar (const T *);
+
+const A a;
+const C c;
+
+const A foo (const A d, const C e)
+{
+ const A f;
+ const B b = { 4 };
+ A g;
+ #pragma omp parallel private (a) // { dg-error "predetermined" }
+ bar (&a);
+ #pragma omp parallel private (b) // { dg-error "predetermined" }
+ bar (&b);
+ #pragma omp parallel private (c)
+ bar (&c);
+ #pragma omp parallel private (d) // { dg-error "predetermined" }
+ bar (&d);
+ #pragma omp parallel private (e)
+ bar (&e);
+ #pragma omp parallel private (f) // { dg-error "predetermined" }
+ bar (&f);
+ #pragma omp parallel private (g)
+ bar (&g);
+ return f;
+}
--- /dev/null
+// { dg-do compile }
+
+struct T
+{
+ int i;
+ mutable int j;
+};
+struct S
+{
+ const static int d = 1;
+ const static T e;
+ void foo (int, T);
+};
+
+const int S::d;
+const T S::e = { 2, 3 };
+
+void bar (const int &);
+
+void
+S::foo (const int x, const T y)
+{
+ #pragma omp parallel firstprivate (x)
+ bar (x);
+ #pragma omp parallel firstprivate (d)
+ bar (d);
+ #pragma omp parallel firstprivate (y)
+ bar (y.i);
+ #pragma omp parallel firstprivate (e) // { dg-error "is predetermined" }
+ bar (e.i);
+ #pragma omp parallel shared (x) // { dg-error "is predetermined" }
+ bar (x);
+ #pragma omp parallel shared (d) // { dg-error "is predetermined" }
+ bar (d);
+ #pragma omp parallel shared (e) // { dg-error "is predetermined" }
+ bar (e.i);
+ #pragma omp parallel shared (y)
+ bar (y.i);
+ #pragma omp parallel private (x) // { dg-error "is predetermined" }
+ bar (x);
+ #pragma omp parallel private (d) // { dg-error "is predetermined" }
+ bar (d);
+ #pragma omp parallel private (y)
+ bar (y.i);
+ #pragma omp parallel private (e) // { dg-error "is predetermined" }
+ bar (e.i);
+}
--- /dev/null
+/* { dg-do compile } */
+/* { dg-options "-fopenmp" } */
+
+int x = 6;
+
+int
+main ()
+{
+ int v;
+ #pragma omp atomic
+ x = x * 7 + 6; /* { dg-error "expected" } */
+ #pragma omp atomic
+ x = x * 7 ^ 6; /* { dg-error "expected" } */
+ #pragma omp atomic update
+ x = x - 8 + 6; /* { dg-error "expected" } */
+ #pragma omp atomic
+ x = x ^ 7 | 2; /* { dg-error "expected" } */
+ #pragma omp atomic
+ x = x / 7 * 2; /* { dg-error "expected" } */
+ #pragma omp atomic
+ x = x / 7 / 2; /* { dg-error "expected" } */
+ #pragma omp atomic capture
+ v = x = x | 6; /* { dg-error "invalid operator" } */
+ #pragma omp atomic capture
+ { v = x; x = x * 7 + 6; } /* { dg-error "expected" } */
+ #pragma omp atomic capture
+ { v = x; x = x * 7 ^ 6; } /* { dg-error "expected" } */
+ #pragma omp atomic capture
+ { v = x; x = x - 8 + 6; } /* { dg-error "expected" } */
+ #pragma omp atomic capture
+ { v = x; x = x ^ 7 | 2; } /* { dg-error "expected" } */
+ #pragma omp atomic capture
+ { v = x; x = x / 7 * 2; } /* { dg-error "expected" } */
+ #pragma omp atomic capture
+ { v = x; x = x / 7 / 2; } /* { dg-error "expected" } */
+ #pragma omp atomic capture
+ { x = x * 7 + 6; v = x; } /* { dg-error "expected" } */
+ #pragma omp atomic capture
+ { x = x * 7 ^ 6; v = x; } /* { dg-error "expected" } */
+ #pragma omp atomic capture
+ { x = x - 8 + 6; v = x; } /* { dg-error "expected" } */
+ #pragma omp atomic capture
+ { x = x ^ 7 | 2; v = x; } /* { dg-error "expected" } */
+ (void) v;
+ return 0;
+}
#pragma omp atomic
x %= 2; /* { dg-error "invalid operator" } */
#pragma omp atomic
- x = x + 1; /* { dg-error "invalid operator" } */
+ x = x + 1;
#pragma omp atomic
- x = 1; /* { dg-error "invalid operator" } */
+ x = 1; /* { dg-error "invalid form" } */
#pragma omp atomic
++y; /* { dg-error "read-only variable" } */
#pragma omp atomic
;
#pragma omp p private (c) /* { dg-error "predetermined 'shared'" } */
;
-#pragma omp p firstprivate (c) /* { dg-error "predetermined 'shared'" } */
+#pragma omp p firstprivate (c)
;
#pragma omp p for lastprivate (c) /* { dg-error "predetermined 'shared'" } */
for (i = 0; i < 10; i++)
!$omp end parallel
ip3 = loc (i)
-!$omp parallel firstprivate (ip3) ! { dg-error "Cray pointer 'ip3' in FIRSTPRIVATE clause" }
+!$omp parallel firstprivate (ip3)
!$omp end parallel
-!$omp parallel do lastprivate (ip4) ! { dg-error "Cray pointer 'ip4' in LASTPRIVATE clause" }
+!$omp parallel do lastprivate (ip4)
do i = 1, 10
if (i .eq. 10) ip4 = loc (i)
end do
--- /dev/null
+ real :: r1, r2
+ complex :: c1, c2
+ integer :: i1, i2
+!$omp atomic write
+ c1 = 0
+!$omp atomic write
+ r2 = 0
+!$omp atomic write
+ i2 = 0
+!$omp atomic read
+ r1 = c1
+!$omp atomic read
+ c2 = r2
+!$omp atomic read
+ i1 = r2
+!$omp atomic read
+ c2 = i2
+!$omp atomic write
+ c1 = r1
+!$omp atomic write
+ r2 = c2
+!$omp atomic write
+ r2 = i1
+!$omp atomic write
+ i2 = c2
+!$omp end atomic
+!$omp atomic write
+ c1 = 1 + 2 + r1
+!$omp atomic write
+ r2 = c2 + 2 + 3
+!$omp atomic write
+ r2 = 3 + 4 + i1
+!$omp atomic write
+ i2 = c2 + 4 + 5
+!$omp atomic
+ c1 = c1 * 2.
+!$omp atomic update
+ r2 = r2 / 4
+!$omp end atomic
+!$omp atomic update
+ i2 = i2 + 8
+!$omp atomic capture
+ c1 = c1 * 2.
+ r1 = c1
+!$omp end atomic
+!$omp atomic capture
+ c2 = r2
+ r2 = r2 / 4
+!$omp end atomic
+!$omp atomic capture
+ i2 = i2 + 8
+ c2 = i2
+!$omp end atomic
+end
if (OMP_CLAUSE_SCHEDULE_CHUNK_EXPR (clause) == NULL)
break;
/* FALLTHRU */
+ case OMP_CLAUSE_FINAL:
case OMP_CLAUSE_IF:
case OMP_CLAUSE_NUM_THREADS:
wi->val_only = true;
case OMP_CLAUSE_COPYIN:
case OMP_CLAUSE_COLLAPSE:
case OMP_CLAUSE_UNTIED:
+ case OMP_CLAUSE_MERGEABLE:
break;
default:
if (OMP_CLAUSE_SCHEDULE_CHUNK_EXPR (clause) == NULL)
break;
/* FALLTHRU */
+ case OMP_CLAUSE_FINAL:
case OMP_CLAUSE_IF:
case OMP_CLAUSE_NUM_THREADS:
wi->val_only = true;
case OMP_CLAUSE_COPYIN:
case OMP_CLAUSE_COLLAPSE:
case OMP_CLAUSE_UNTIED:
+ case OMP_CLAUSE_MERGEABLE:
break;
default:
pp_character (buffer, ')');
break;
+ case OMP_CLAUSE_FINAL:
+ pp_string (buffer, "final(");
+ dump_generic_node (buffer, OMP_CLAUSE_FINAL_EXPR (clause),
+ spc, flags, false);
+ pp_character (buffer, ')');
+ break;
+
+ case OMP_CLAUSE_MERGEABLE:
+ pp_string (buffer, "mergeable");
+ break;
+
default:
/* Should never happen. */
dump_generic_node (buffer, clause, spc, flags, false);
dump_generic_node (buffer, TREE_OPERAND (node, 1), spc, flags, false);
break;
+ case OMP_ATOMIC_READ:
+ pp_string (buffer, "#pragma omp atomic read");
+ newline_and_indent (buffer, spc + 2);
+ dump_generic_node (buffer, TREE_OPERAND (node, 0), spc, flags, false);
+ pp_space (buffer);
+ break;
+
+ case OMP_ATOMIC_CAPTURE_OLD:
+ case OMP_ATOMIC_CAPTURE_NEW:
+ pp_string (buffer, "#pragma omp atomic capture");
+ newline_and_indent (buffer, spc + 2);
+ dump_generic_node (buffer, TREE_OPERAND (node, 0), spc, flags, false);
+ pp_space (buffer);
+ pp_character (buffer, '=');
+ pp_space (buffer);
+ dump_generic_node (buffer, TREE_OPERAND (node, 1), spc, flags, false);
+ break;
+
case OMP_SINGLE:
pp_string (buffer, "#pragma omp single");
dump_omp_clauses (buffer, OMP_SINGLE_CLAUSES (node), spc, flags);
0, /* OMP_CLAUSE_ORDERED */
0, /* OMP_CLAUSE_DEFAULT */
3, /* OMP_CLAUSE_COLLAPSE */
- 0 /* OMP_CLAUSE_UNTIED */
+ 0, /* OMP_CLAUSE_UNTIED */
+ 1, /* OMP_CLAUSE_FINAL */
+ 0 /* OMP_CLAUSE_MERGEABLE */
};
const char * const omp_clause_code_name[] =
"ordered",
"default",
"collapse",
- "untied"
+ "untied",
+ "final",
+ "mergeable"
};
case OMP_CLAUSE_FIRSTPRIVATE:
case OMP_CLAUSE_COPYIN:
case OMP_CLAUSE_COPYPRIVATE:
+ case OMP_CLAUSE_FINAL:
case OMP_CLAUSE_IF:
case OMP_CLAUSE_NUM_THREADS:
case OMP_CLAUSE_SCHEDULE:
case OMP_CLAUSE_ORDERED:
case OMP_CLAUSE_DEFAULT:
case OMP_CLAUSE_UNTIED:
+ case OMP_CLAUSE_MERGEABLE:
WALK_SUBTREE_TAIL (OMP_CLAUSE_CHAIN (*tp));
case OMP_CLAUSE_LASTPRIVATE:
build_fold_indirect_ref of the address. */
DEFTREECODE (OMP_ATOMIC, "omp_atomic", tcc_statement, 2)
+/* OpenMP - #pragma omp atomic read
+ Operand 0: The address at which the atomic operation is to be performed.
+ This address should be stabilized with save_expr. */
+DEFTREECODE (OMP_ATOMIC_READ, "omp_atomic_read", tcc_statement, 1)
+
+/* OpenMP - #pragma omp atomic capture
+ Operand 0: The address at which the atomic operation is to be performed.
+ This address should be stabilized with save_expr.
+ Operand 1: The expression to evaluate. When the old value of the object
+ at the address is used in the expression, it should appear as if
+ build_fold_indirect_ref of the address.
+ OMP_ATOMIC_CAPTURE_OLD returns the old memory content,
+ OMP_ATOMIC_CAPTURE_NEW the new value. */
+DEFTREECODE (OMP_ATOMIC_CAPTURE_OLD, "omp_atomic_capture_old", tcc_statement, 2)
+DEFTREECODE (OMP_ATOMIC_CAPTURE_NEW, "omp_atomic_capture_new", tcc_statement, 2)
+
/* OpenMP clauses. */
DEFTREECODE (OMP_CLAUSE, "omp_clause", tcc_exceptional, 0)
OMP_CLAUSE_COLLAPSE,
/* OpenMP clause: untied. */
- OMP_CLAUSE_UNTIED
+ OMP_CLAUSE_UNTIED,
+
+ /* OpenMP clause: final (scalar-expression). */
+ OMP_CLAUSE_FINAL,
+
+ /* OpenMP clause: mergeable. */
+ OMP_CLAUSE_MERGEABLE
};
\f
/* The definition of tree nodes fills the next several pages. */
#define OMP_CLAUSE_LASTPRIVATE_GIMPLE_SEQ(NODE) \
(OMP_CLAUSE_CHECK (NODE))->omp_clause.gimple_reduction_init
+#define OMP_CLAUSE_FINAL_EXPR(NODE) \
+ OMP_CLAUSE_OPERAND (OMP_CLAUSE_SUBCODE_CHECK (NODE, OMP_CLAUSE_FINAL), 0)
#define OMP_CLAUSE_IF_EXPR(NODE) \
OMP_CLAUSE_OPERAND (OMP_CLAUSE_SUBCODE_CHECK (NODE, OMP_CLAUSE_IF), 0)
#define OMP_CLAUSE_NUM_THREADS_EXPR(NODE) \
+2011-08-02 Jakub Jelinek <jakub@redhat.com>
+
+ PR fortran/42041
+ PR fortran/46752
+ * omp.h.in (omp_in_final): New prototype.
+ * omp_lib.f90.in (omp_in_final): New interface.
+ (omp_integer_kind, omp_logical_kind): Remove
+ and replace all its uses in the module with 4.
+ (openmp_version): Change to 201107.
+ * omp_lib.h.in (omp_sched_static, omp_sched_dynamic,
+ omp_sched_guided, omp_sched_auto): Use omp_sched_kind
+ kind for the parameters.
+ (omp_in_final): New external.
+ (openmp_version): Change to 201107.
+ * task.c (omp_in_final): New function.
+ (gomp_init_task): Initialize final_task.
+ (GOMP_task): Remove unused attribute from flags. Handle final
+ tasks.
+ (GOMP_taskyield): New function.
+ (omp_in_final): Return true if if (false) or final (true) task
+ or descendant of final (true).
+ * fortran.c (omp_in_final_): New function.
+ * libgomp.map (OMP_3.1): Export omp_in_final and omp_in_final_.
+ (GOMP_3.0): Export GOMP_taskyield.
+ * env.c (gomp_nthreads_var_list, gomp_nthreads_var_list_len): New
+ variables.
+ (parse_unsigned_long_list): New function.
+ (initialize_env): Use it for OMP_NUM_THREADS. Call parse_boolean
+ with "OMP_PROC_BIND". If OMP_PROC_BIND=true, call gomp_init_affinity
+ even if parse_affinity returned false.
+ * config/linux/affinity.c (gomp_init_affinity): Handle
+ gomp_cpu_affinity_len == 0.
+ * libgomp_g.h (GOMP_taskyield): New prototype.
+ * libgomp.h (struct gomp_task): Add final_task field.
+ (gomp_nthreads_var_list, gomp_nthreads_var_list_len): New externs.
+ * team.c (gomp_team_start): Override new task's nthreads_var icv
+ if list form OMP_NUM_THREADS has been used and it has value for
+ the new nesting level.
+
+ * testsuite/libgomp.c/atomic-11.c: New test.
+ * testsuite/libgomp.c/atomic-12.c: New test.
+ * testsuite/libgomp.c/atomic-13.c: New test.
+ * testsuite/libgomp.c/atomic-14.c: New test.
+ * testsuite/libgomp.c/reduction-6.c: New test.
+ * testsuite/libgomp.c/task-5.c: New test.
+ * testsuite/libgomp.c++/atomic-2.C: New test.
+ * testsuite/libgomp.c++/atomic-3.C: New test.
+ * testsuite/libgomp.c++/atomic-4.C: New test.
+ * testsuite/libgomp.c++/atomic-5.C: New test.
+ * testsuite/libgomp.c++/atomic-6.C: New test.
+ * testsuite/libgomp.c++/atomic-7.C: New test.
+ * testsuite/libgomp.c++/atomic-8.C: New test.
+ * testsuite/libgomp.c++/atomic-9.C: New test.
+ * testsuite/libgomp.c++/task-8.C: New test.
+ * testsuite/libgomp.c++/reduction-4.C: New test.
+ * testsuite/libgomp.fortran/allocatable7.f90: New test.
+ * testsuite/libgomp.fortran/allocatable8.f90: New test.
+ * testsuite/libgomp.fortran/crayptr3.f90: New test.
+ * testsuite/libgomp.fortran/omp_atomic3.f90: New test.
+ * testsuite/libgomp.fortran/omp_atomic4.f90: New test.
+ * testsuite/libgomp.fortran/pointer1.f90: New test.
+ * testsuite/libgomp.fortran/pointer2.f90: New test.
+ * testsuite/libgomp.fortran/task4.f90: New test.
+
+2011-08-02 Tobias Burnus <burnus@net-b.de>
+
+ * libgomp.texi: Update OpenMP spec references to 3.1.
+ (omp_in_final,OMP_PROC_BIND): New sections.
+ (OMP_NUM_THREADS): Document that the value can be now a list.
+ (GOMP_STACKSIZE,GOMP_CPU_AFFINITY): Update @ref.
+
2011-08-02 H.J. Lu <hongjiu.lu@intel.com>
* config/linux/x86/futex.h: Check __x86_64__ instead of
-/* Copyright (C) 2006, 2007, 2008, 2009, 2010 Free Software Foundation, Inc.
+/* Copyright (C) 2006, 2007, 2008, 2009, 2010, 2011
+ Free Software Foundation, Inc.
Contributed by Jakub Jelinek <jakub@redhat.com>.
This file is part of the GNU OpenMP Library (libgomp).
}
CPU_ZERO (&cpusetnew);
- for (widx = idx = 0; idx < gomp_cpu_affinity_len; idx++)
- if (gomp_cpu_affinity[idx] < CPU_SETSIZE
- && CPU_ISSET (gomp_cpu_affinity[idx], &cpuset))
- {
- if (! CPU_ISSET (gomp_cpu_affinity[idx], &cpusetnew))
+ if (gomp_cpu_affinity_len == 0)
+ {
+ unsigned long count = CPU_COUNT (&cpuset);
+ if (count >= 65536)
+ count = 65536;
+ gomp_cpu_affinity = malloc (count * sizeof (unsigned short));
+ if (gomp_cpu_affinity == NULL)
+ {
+ gomp_error ("not enough memory to store CPU affinity list");
+ return;
+ }
+ for (widx = idx = 0; widx < count && idx < 65536; idx++)
+ if (CPU_ISSET (idx, &cpuset))
{
cpus++;
- CPU_SET (gomp_cpu_affinity[idx], &cpusetnew);
+ gomp_cpu_affinity[widx++] = idx;
}
- gomp_cpu_affinity[widx++] = gomp_cpu_affinity[idx];
- }
+ }
+ else
+ for (widx = idx = 0; idx < gomp_cpu_affinity_len; idx++)
+ if (gomp_cpu_affinity[idx] < CPU_SETSIZE
+ && CPU_ISSET (gomp_cpu_affinity[idx], &cpuset))
+ {
+ if (! CPU_ISSET (gomp_cpu_affinity[idx], &cpusetnew))
+ {
+ cpus++;
+ CPU_SET (gomp_cpu_affinity[idx], &cpusetnew);
+ }
+ gomp_cpu_affinity[widx++] = gomp_cpu_affinity[idx];
+ }
if (widx == 0)
{
#endif
unsigned long gomp_available_cpus = 1, gomp_managed_threads = 1;
unsigned long long gomp_spin_count_var, gomp_throttled_spin_count_var;
+unsigned long *gomp_nthreads_var_list, gomp_nthreads_var_list_len;
/* Parse the OMP_SCHEDULE environment variable. */
return false;
}
+/* Parse an unsigned long list environment variable. Return true if one was
+ present and it was successfully parsed. */
+
+static bool
+parse_unsigned_long_list (const char *name, unsigned long *p1stvalue,
+ unsigned long **pvalues,
+ unsigned long *pnvalues)
+{
+ char *env, *end;
+ unsigned long value, *values = NULL;
+
+ env = getenv (name);
+ if (env == NULL)
+ return false;
+
+ while (isspace ((unsigned char) *env))
+ ++env;
+ if (*env == '\0')
+ goto invalid;
+
+ errno = 0;
+ value = strtoul (env, &end, 10);
+ if (errno || (long) value <= 0)
+ goto invalid;
+
+ while (isspace ((unsigned char) *end))
+ ++end;
+ if (*end != '\0')
+ {
+ if (*end == ',')
+ {
+ unsigned long nvalues = 0, nalloced = 0;
+
+ do
+ {
+ env = end + 1;
+ if (nvalues == nalloced)
+ {
+ unsigned long *n;
+ nalloced = nalloced ? nalloced * 2 : 16;
+ n = realloc (values, nalloced * sizeof (unsigned long));
+ if (n == NULL)
+ {
+ free (values);
+ gomp_error ("Out of memory while trying to parse"
+ " environment variable %s", name);
+ return false;
+ }
+ values = n;
+ if (nvalues == 0)
+ values[nvalues++] = value;
+ }
+
+ while (isspace ((unsigned char) *env))
+ ++env;
+ if (*env == '\0')
+ goto invalid;
+
+ errno = 0;
+ value = strtoul (env, &end, 10);
+ if (errno || (long) value <= 0)
+ goto invalid;
+
+ values[nvalues++] = value;
+ while (isspace ((unsigned char) *end))
+ ++end;
+ if (*end == '\0')
+ break;
+ if (*end != ',')
+ goto invalid;
+ }
+ while (1);
+ *p1stvalue = values[0];
+ *pvalues = values;
+ *pnvalues = nvalues;
+ return true;
+ }
+ goto invalid;
+ }
+
+ *p1stvalue = value;
+ return true;
+
+ invalid:
+ free (values);
+ gomp_error ("Invalid value for environment variable %s", name);
+ return false;
+}
+
/* Parse the OMP_STACKSIZE environment varible. Return true if one was
present and it was successfully parsed. */
{
unsigned long stacksize;
int wait_policy;
+ bool bind_var = false;
/* Do a compile time check that mkomp_h.pl did good job. */
omp_check_defines ();
parse_schedule ();
parse_boolean ("OMP_DYNAMIC", &gomp_global_icv.dyn_var);
parse_boolean ("OMP_NESTED", &gomp_global_icv.nest_var);
+ parse_boolean ("OMP_PROC_BIND", &bind_var);
parse_unsigned_long ("OMP_MAX_ACTIVE_LEVELS", &gomp_max_active_levels_var,
true);
parse_unsigned_long ("OMP_THREAD_LIMIT", &gomp_thread_limit_var, false);
#endif
gomp_init_num_threads ();
gomp_available_cpus = gomp_global_icv.nthreads_var;
- if (!parse_unsigned_long ("OMP_NUM_THREADS", &gomp_global_icv.nthreads_var,
- false))
+ if (!parse_unsigned_long_list ("OMP_NUM_THREADS",
+ &gomp_global_icv.nthreads_var,
+ &gomp_nthreads_var_list,
+ &gomp_nthreads_var_list_len))
gomp_global_icv.nthreads_var = gomp_available_cpus;
- if (parse_affinity ())
+ if (parse_affinity () || bind_var)
gomp_init_affinity ();
wait_policy = parse_wait_policy ();
if (!parse_spincount ("GOMP_SPINCOUNT", &gomp_spin_count_var))
ialias_redirect (omp_get_ancestor_thread_num)
ialias_redirect (omp_get_team_size)
ialias_redirect (omp_get_active_level)
+ialias_redirect (omp_in_final)
#endif
#ifndef LIBGOMP_GNU_SYMBOL_VERSIONING
{
return omp_get_active_level ();
}
+
+int32_t
+omp_in_final_ (void)
+{
+ return omp_in_final ();
+}
-/* Copyright (C) 2005, 2007, 2008, 2009, 2010 Free Software Foundation, Inc.
+/* Copyright (C) 2005, 2007, 2008, 2009, 2010, 2011
+ Free Software Foundation, Inc.
Contributed by Richard Henderson <rth@redhat.com>.
This file is part of the GNU OpenMP Library (libgomp).
extern unsigned long gomp_max_active_levels_var;
extern unsigned long long gomp_spin_count_var, gomp_throttled_spin_count_var;
extern unsigned long gomp_available_cpus, gomp_managed_threads;
+extern unsigned long *gomp_nthreads_var_list, gomp_nthreads_var_list_len;
enum gomp_task_kind
{
enum gomp_task_kind kind;
bool in_taskwait;
bool in_tied_task;
+ bool final_task;
gomp_sem_t taskwait_sem;
};
omp_unset_nest_lock_;
} OMP_2.0;
+OMP_3.1 {
+ global:
+ omp_in_final;
+ omp_in_final_;
+} OMP_3.0;
+
GOMP_1.0 {
global:
GOMP_atomic_end;
GOMP_loop_ull_static_next;
GOMP_loop_ull_static_start;
} GOMP_1.0;
+
+GOMP_3.0 {
+ global:
+ GOMP_taskyield;
+} GOMP_2.0;
A complete description of all OpenMP directives accepted may be found in
the @uref{http://www.openmp.org, OpenMP Application Program Interface} manual,
-version 3.0.
+version 3.1.
@c ---------------------------------------------------------------------
@chapter Runtime Library Routines
The runtime routines described here are defined by section 3 of the OpenMP
-specifications in version 3.0. The routines are structured in following
+specifications in version 3.1. The routines are structured in following
three parts:
Control threads, processors and the parallel environment.
* omp_get_thread_limit:: Maximum number of threads
* omp_get_thread_num:: Current thread ID
* omp_in_parallel:: Whether a parallel region is active
+* omp_in_final:: Whether in final or included task region
* omp_set_dynamic:: Enable/disable dynamic teams
* omp_set_max_active_levels:: Limits the number of active parallel regions
* omp_set_nested:: Enable/disable nested parallel regions
@ref{omp_get_level}, @ref{omp_get_max_active_levels}, @ref{omp_set_max_active_levels}
@item @emph{Reference}:
-@uref{http://www.openmp.org/, OpenMP specifications v3.0}, section 3.2.19.
+@uref{http://www.openmp.org/, OpenMP specifications v3.1}, section 3.2.19.
@end table
@ref{omp_get_level}, @ref{omp_get_thread_num}, @ref{omp_get_team_size}
@item @emph{Reference}:
-@uref{http://www.openmp.org/, OpenMP specifications v3.0}, section 3.2.17.
+@uref{http://www.openmp.org/, OpenMP specifications v3.1}, section 3.2.17.
@end table
@ref{omp_set_dynamic}, @ref{OMP_DYNAMIC}
@item @emph{Reference}:
-@uref{http://www.openmp.org/, OpenMP specifications v3.0}, section 3.2.8.
+@uref{http://www.openmp.org/, OpenMP specifications v3.1}, section 3.2.8.
@end table
@ref{omp_get_active_level}
@item @emph{Reference}:
-@uref{http://www.openmp.org/, OpenMP specifications v3.0}, section 3.2.16.
+@uref{http://www.openmp.org/, OpenMP specifications v3.1}, section 3.2.16.
@end table
@ref{omp_set_max_active_levels}, @ref{omp_get_active_level}
@item @emph{Reference}:
-@uref{http://www.openmp.org/, OpenMP specifications v3.0}, section 3.2.14.
+@uref{http://www.openmp.org/, OpenMP specifications v3.1}, section 3.2.15.
@end table
@ref{omp_set_num_threads}, @ref{omp_set_dynamic}, @ref{omp_get_thread_limit}
@item @emph{Reference}:
-@uref{http://www.openmp.org/, OpenMP specifications v3.0}, section 3.2.3.
+@uref{http://www.openmp.org/, OpenMP specifications v3.1}, section 3.2.3.
@end table
@ref{omp_set_nested}, @ref{OMP_NESTED}
@item @emph{Reference}:
-@uref{http://www.openmp.org/, OpenMP specifications v3.0}, section 3.2.10.
+@uref{http://www.openmp.org/, OpenMP specifications v3.1}, section 3.2.10.
@end table
@end multitable
@item @emph{Reference}:
-@uref{http://www.openmp.org/, OpenMP specifications v3.0}, section 3.2.5.
+@uref{http://www.openmp.org/, OpenMP specifications v3.1}, section 3.2.5.
@end table
@ref{omp_get_max_threads}, @ref{omp_set_num_threads}, @ref{OMP_NUM_THREADS}
@item @emph{Reference}:
-@uref{http://www.openmp.org/, OpenMP specifications v3.0}, section 3.2.2.
+@uref{http://www.openmp.org/, OpenMP specifications v3.1}, section 3.2.2.
@end table
@item @emph{C/C++}
@multitable @columnfractions .20 .80
-@item @emph{Prototype}: @tab @code{omp_schedule(omp_sched_t *kind, int *modifier);}
+@item @emph{Prototype}: @tab @code{void omp_schedule(omp_sched_t *kind, int *modifier);}
@end multitable
@item @emph{Fortran}:
@ref{omp_set_schedule}, @ref{OMP_SCHEDULE}
@item @emph{Reference}:
-@uref{http://www.openmp.org/, OpenMP specifications v3.0}, section 3.2.12.
+@uref{http://www.openmp.org/, OpenMP specifications v3.1}, section 3.2.12.
@end table
@ref{omp_get_num_threads}, @ref{omp_get_level}, @ref{omp_get_ancestor_thread_num}
@item @emph{Reference}:
-@uref{http://www.openmp.org/, OpenMP specifications v3.0}, section 3.2.18.
+@uref{http://www.openmp.org/, OpenMP specifications v3.1}, section 3.2.18.
@end table
@ref{omp_get_max_threads}, @ref{OMP_THREAD_LIMIT}
@item @emph{Reference}:
-@uref{http://www.openmp.org/, OpenMP specifications v3.0}, section 3.2.13.
+@uref{http://www.openmp.org/, OpenMP specifications v3.1}, section 3.2.13.
@end table
@ref{omp_get_num_threads}, @ref{omp_get_ancestor_thread_num}
@item @emph{Reference}:
-@uref{http://www.openmp.org/, OpenMP specifications v3.0}, section 3.2.4.
+@uref{http://www.openmp.org/, OpenMP specifications v3.1}, section 3.2.4.
@end table
@end multitable
@item @emph{Reference}:
-@uref{http://www.openmp.org/, OpenMP specifications v3.0}, section 3.2.6.
+@uref{http://www.openmp.org/, OpenMP specifications v3.1}, section 3.2.6.
+@end table
+
+
+@node omp_in_final
+@section @code{omp_in_final} -- Whether in final or included task region
+@table @asis
+@item @emph{Description}:
+This function returns @code{true} if currently running in a final
+or included task region, @code{false} otherwise. Here, @code{true}
+and @code{false} represent their language-specific counterparts.
+
+@item @emph{C/C++}:
+@multitable @columnfractions .20 .80
+@item @emph{Prototype}: @tab @code{int omp_in_final(void);}
+@end multitable
+
+@item @emph{Fortran}:
+@multitable @columnfractions .20 .80
+@item @emph{Interface}: @tab @code{logical function omp_in_final()}
+@end multitable
+
+@item @emph{Reference}:
+@uref{http://www.openmp.org/, OpenMP specifications v3.1}, section 3.2.20.
@end table
@ref{OMP_DYNAMIC}, @ref{omp_get_dynamic}
@item @emph{Reference}:
-@uref{http://www.openmp.org/, OpenMP specifications v3.0}, section 3.2.7.
+@uref{http://www.openmp.org/, OpenMP specifications v3.1}, section 3.2.7.
@end table
@ref{omp_get_max_active_levels}, @ref{omp_get_active_level}
@item @emph{Reference}:
-@uref{http://www.openmp.org/, OpenMP specifications v3.0}, section 3.2.14.
+@uref{http://www.openmp.org/, OpenMP specifications v3.1}, section 3.2.14.
@end table
@ref{OMP_NESTED}, @ref{omp_get_nested}
@item @emph{Reference}:
-@uref{http://www.openmp.org/, OpenMP specifications v3.0}, section 3.2.9.
+@uref{http://www.openmp.org/, OpenMP specifications v3.1}, section 3.2.9.
@end table
@ref{OMP_NUM_THREADS}, @ref{omp_get_num_threads}, @ref{omp_get_max_threads}
@item @emph{Reference}:
-@uref{http://www.openmp.org/, OpenMP specifications v3.0}, section 3.2.1.
+@uref{http://www.openmp.org/, OpenMP specifications v3.1}, section 3.2.1.
@end table
@item @emph{C/C++}
@multitable @columnfractions .20 .80
-@item @emph{Prototype}: @tab @code{int omp_set_schedule(omp_sched_t *kind, int *modifier);}
+@item @emph{Prototype}: @tab @code{void omp_set_schedule(omp_sched_t *kind, int *modifier);}
@end multitable
@item @emph{Fortran}:
@ref{OMP_SCHEDULE}
@item @emph{Reference}:
-@uref{http://www.openmp.org/, OpenMP specifications v3.0}, section 3.2.11.
+@uref{http://www.openmp.org/, OpenMP specifications v3.1}, section 3.2.11.
@end table
@ref{omp_destroy_lock}
@item @emph{Reference}:
-@uref{http://www.openmp.org/, OpenMP specifications v3.0}, section 3.3.1.
+@uref{http://www.openmp.org/, OpenMP specifications v3.1}, section 3.3.1.
@end table
@ref{omp_init_lock}, @ref{omp_test_lock}, @ref{omp_unset_lock}
@item @emph{Reference}:
-@uref{http://www.openmp.org/, OpenMP specifications v3.0}, section 3.3.3.
+@uref{http://www.openmp.org/, OpenMP specifications v3.1}, section 3.3.3.
@end table
@item @emph{Fortran}:
@multitable @columnfractions .20 .80
-@item @emph{Interface}: @tab @code{subroutine omp_test_lock(lock)}
-@item @tab @code{logical(omp_logical_kind) :: omp_test_lock}
+@item @emph{Interface}: @tab @code{logical function omp_test_lock(lock)}
@item @tab @code{integer(omp_lock_kind), intent(inout) :: lock}
@end multitable
@ref{omp_init_lock}, @ref{omp_set_lock}, @ref{omp_set_lock}
@item @emph{Reference}:
-@uref{http://www.openmp.org/, OpenMP specifications v3.0}, section 3.3.5.
+@uref{http://www.openmp.org/, OpenMP specifications v3.1}, section 3.3.5.
@end table
or @code{omp_test_lock} before. In addition, the lock must be held by the
thread calling @code{omp_unset_lock}. Then, the lock becomes unlocked. If one
or more threads attempted to set the lock before, one of them is chosen to,
-again, set the lock for itself.
+again, set the lock to itself.
@item @emph{C/C++}:
@multitable @columnfractions .20 .80
@ref{omp_set_lock}, @ref{omp_test_lock}
@item @emph{Reference}:
-@uref{http://www.openmp.org/, OpenMP specifications v3.0}, section 3.3.4.
+@uref{http://www.openmp.org/, OpenMP specifications v3.1}, section 3.3.4.
@end table
@ref{omp_init_lock}
@item @emph{Reference}:
-@uref{http://www.openmp.org/, OpenMP specifications v3.0}, section 3.3.2.
+@uref{http://www.openmp.org/, OpenMP specifications v3.1}, section 3.3.2.
@end table
@ref{omp_destroy_nest_lock}
@item @emph{Reference}:
-@uref{http://www.openmp.org/, OpenMP specifications v3.0}, section 3.3.1.
+@uref{http://www.openmp.org/, OpenMP specifications v3.1}, section 3.3.1.
@end table
Before setting a nested lock, the lock variable must be initialized by
@code{omp_init_nest_lock}. The calling thread is blocked until the lock
is available. If the lock is already held by the current thread, the
-nesting count for the lock in incremented.
+nesting count for the lock is incremented.
@item @emph{C/C++}:
@multitable @columnfractions .20 .80
@ref{omp_init_nest_lock}, @ref{omp_unset_nest_lock}
@item @emph{Reference}:
-@uref{http://www.openmp.org/, OpenMP specifications v3.0}, section 3.3.3.
+@uref{http://www.openmp.org/, OpenMP specifications v3.1}, section 3.3.3.
@end table
@item @emph{Fortran}:
@multitable @columnfractions .20 .80
-@item @emph{Interface}: @tab @code{integer function omp_test_nest_lock(lock)}
-@item @tab @code{integer(omp_integer_kind) :: omp_test_nest_lock}
+@item @emph{Interface}: @tab @code{logical function omp_test_nest_lock(lock)}
@item @tab @code{integer(omp_nest_lock_kind), intent(inout) :: lock}
@end multitable
@ref{omp_init_lock}, @ref{omp_set_lock}, @ref{omp_set_lock}
@item @emph{Reference}:
-@uref{http://www.openmp.org/, OpenMP specifications v3.0}, section 3.3.5.
+@uref{http://www.openmp.org/, OpenMP specifications v3.1}, section 3.3.5.
@end table
or @code{omp_test_nested_lock} before. In addition, the lock must be held by the
thread calling @code{omp_unset_nested_lock}. If the nesting count drops to zero, the
lock becomes unlocked. If one ore more threads attempted to set the lock before,
-one of them is chosen to, again, set the lock for itself.
+one of them is chosen to, again, set the lock to itself.
@item @emph{C/C++}:
@multitable @columnfractions .20 .80
@ref{omp_set_nest_lock}
@item @emph{Reference}:
-@uref{http://www.openmp.org/, OpenMP specifications v3.0}, section 3.3.4.
+@uref{http://www.openmp.org/, OpenMP specifications v3.1}, section 3.3.4.
@end table
@ref{omp_init_lock}
@item @emph{Reference}:
-@uref{http://www.openmp.org/, OpenMP specifications v3.0}, section 3.3.2.
+@uref{http://www.openmp.org/, OpenMP specifications v3.1}, section 3.3.2.
@end table
@ref{omp_get_wtime}
@item @emph{Reference}:
-@uref{http://www.openmp.org/, OpenMP specifications v3.0}, section 3.4.2.
+@uref{http://www.openmp.org/, OpenMP specifications v3.1}, section 3.4.2.
@end table
@ref{omp_get_wtick}
@item @emph{Reference}:
-@uref{http://www.openmp.org/, OpenMP specifications v3.0}, section 3.4.1.
+@uref{http://www.openmp.org/, OpenMP specifications v3.1}, section 3.4.1.
@end table
The variables @env{OMP_DYNAMIC}, @env{OMP_MAX_ACTIVE_LEVELS},
@env{OMP_NESTED}, @env{OMP_NUM_THREADS}, @env{OMP_SCHEDULE},
@env{OMP_STACKSIZE},@env{OMP_THREAD_LIMIT} and @env{OMP_WAIT_POLICY}
-are defined by section 4 of the OpenMP specifications in version 3.0,
+are defined by section 4 of the OpenMP specifications in version 3.1,
while @env{GOMP_CPU_AFFINITY} and @env{GOMP_STACKSIZE} are GNU
extensions.
* OMP_SCHEDULE:: How threads are scheduled
* OMP_THREAD_LIMIT:: Set the maximum number of threads
* OMP_WAIT_POLICY:: How waiting threads are handled
+* OMP_PROC_BIND:: Whether theads may be moved between CPUs
* GOMP_CPU_AFFINITY:: Bind threads to specific CPUs
* GOMP_STACKSIZE:: Set default thread stack size
@end menu
@ref{omp_set_dynamic}
@item @emph{Reference}:
-@uref{http://www.openmp.org/, OpenMP specifications v3.0}, section 4.3
+@uref{http://www.openmp.org/, OpenMP specifications v3.1}, section 4.3
@end table
@table @asis
@item @emph{Description}:
Specifies the initial value for the maximum number of nested parallel
-regions. The value of this variable shall be positive integer.
+regions. The value of this variable shall be a positive integer.
If undefined, the number of active levels is unlimited.
@item @emph{See also}:
@ref{omp_set_max_active_levels}
@item @emph{Reference}:
-@uref{http://www.openmp.org/, OpenMP specifications v3.0}, section 4.7
+@uref{http://www.openmp.org/, OpenMP specifications v3.1}, section 4.8
@end table
@ref{omp_set_nested}
@item @emph{Reference}:
-@uref{http://www.openmp.org/, OpenMP specifications v3.0}, section 4.4
+@uref{http://www.openmp.org/, OpenMP specifications v3.1}, section 4.5
@end table
@table @asis
@item @emph{Description}:
Specifies the default number of threads to use in parallel regions. The
-value of this variable shall be a positive integer. If undefined one thread
-per CPU is used.
+value of this variable shall be a comma-separated list of positive integers;
+the value specified the number of threads to use for the corresponding nested
+level. If undefined one thread per CPU is used.
@item @emph{See also}:
@ref{omp_set_num_threads}
@item @emph{Reference}:
-@uref{http://www.openmp.org/, OpenMP specifications v3.0}, section 4.2
+@uref{http://www.openmp.org/, OpenMP specifications v3.1}, section 4.2
@end table
@ref{omp_set_schedule}
@item @emph{Reference}:
-@uref{http://www.openmp.org/, OpenMP specifications v3.0}, sections 2.5.1 and 4.1
+@uref{http://www.openmp.org/, OpenMP specifications v3.1}, sections 2.5.1 and 4.1
@end table
is suffixed by @code{B}, @code{K}, @code{M} or @code{G}, in which
case the size is, respectively, in bytes, kilobytes, megabytes
or gigabytes. This is different from @code{pthread_attr_setstacksize}
-which gets the number of bytes as an argument. If the stacksize cannot
+which gets the number of bytes as an argument. If the stack size cannot
be set due to system constraints, an error is reported and the initial
-stacksize is left unchanged. If undefined, the stack size is system
+stack size is left unchanged. If undefined, the stack size is system
dependent.
@item @emph{Reference}:
-@uref{http://www.openmp.org/, OpenMP specifications v3.0}, sections 4.5
+@uref{http://www.openmp.org/, OpenMP specifications v3.1}, sections 4.6
@end table
@ref{omp_get_thread_limit}
@item @emph{Reference}:
-@uref{http://www.openmp.org/, OpenMP specifications v3.0}, section 4.8
+@uref{http://www.openmp.org/, OpenMP specifications v3.1}, section 4.9
@end table
they should.
@item @emph{Reference}:
-@uref{http://www.openmp.org/, OpenMP specifications v3.0}, sections 4.6
+@uref{http://www.openmp.org/, OpenMP specifications v3.1}, sections 4.7
+@end table
+
+
+
+@node OMP_PROC_BIND
+@section @env{OMP_PROC_BIND} -- Whether theads may be moved between CPUs
+@cindex Environment Variable
+@table @asis
+@item @emph{Description}:
+Specifies whether threads may be moved between processors. If set to
+@code{true}, OpenMP theads should not be moved, if set to @code{false}
+they may be moved.
+
+@item @emph{See also}:
+@ref{GOMP_CPU_AFFINITY}
+
+@item @emph{Reference}:
+@uref{http://www.openmp.org/, OpenMP specifications v3.1}, sections 4.4
@end table
If this environment variable is omitted, the host system will handle the
assignment of threads to CPUs.
+
+@item @emph{See also}:
+@ref{OMP_PROC_BIND}
@end table
@item @emph{Description}:
Set the default thread stack size in kilobytes. This is different from
@code{pthread_attr_setstacksize} which gets the number of bytes as an
-argument. If the stacksize cannot be set due to system constraints, an
-error is reported and the initial stacksize is left unchanged. If undefined,
+argument. If the stack size cannot be set due to system constraints, an
+error is reported and the initial stack size is left unchanged. If undefined,
the stack size is system dependent.
@item @emph{See also}:
extern void GOMP_parallel_start (void (*) (void *), void *, unsigned);
extern void GOMP_parallel_end (void);
-/* team.c */
+/* task.c */
extern void GOMP_task (void (*) (void *), void *, void (*) (void *, void *),
long, long, bool, unsigned);
extern void GOMP_taskwait (void);
+extern void GOMP_taskyield (void);
/* sections.c */
-/* Copyright (C) 2005, 2007, 2008, 2009 Free Software Foundation, Inc.
+/* Copyright (C) 2005, 2007, 2008, 2009, 2011 Free Software Foundation, Inc.
Contributed by Richard Henderson <rth@redhat.com>.
This file is part of the GNU OpenMP Library (libgomp).
int omp_get_team_size (int) __GOMP_NOTHROW;
int omp_get_active_level (void) __GOMP_NOTHROW;
+int omp_in_final (void) __GOMP_NOTHROW;
+
#ifdef __cplusplus
}
#endif
-! Copyright (C) 2005, 2007, 2008, 2009 Free Software Foundation, Inc.
+! Copyright (C) 2005, 2007, 2008, 2009, 2011 Free Software Foundation, Inc.
! Contributed by Jakub Jelinek <jakub@redhat.com>.
! This file is part of the GNU OpenMP Library (libgomp).
module omp_lib_kinds
implicit none
- integer, parameter :: omp_integer_kind = 4
- integer, parameter :: omp_logical_kind = 4
integer, parameter :: omp_lock_kind = @OMP_LOCK_KIND@
integer, parameter :: omp_nest_lock_kind = @OMP_NEST_LOCK_KIND@
integer, parameter :: omp_sched_kind = 4
module omp_lib
use omp_lib_kinds
implicit none
- integer, parameter :: openmp_version = 200805
+ integer, parameter :: openmp_version = 201107
integer (omp_sched_kind), parameter :: omp_sched_static = 1
integer (omp_sched_kind), parameter :: omp_sched_dynamic = 2
integer (omp_sched_kind), parameter :: omp_sched_guided = 3
interface
function omp_get_dynamic ()
use omp_lib_kinds
- logical (omp_logical_kind) :: omp_get_dynamic
+ logical (4) :: omp_get_dynamic
end function omp_get_dynamic
end interface
interface
function omp_get_nested ()
use omp_lib_kinds
- logical (omp_logical_kind) :: omp_get_nested
+ logical (4) :: omp_get_nested
end function omp_get_nested
end interface
interface
function omp_in_parallel ()
use omp_lib_kinds
- logical (omp_logical_kind) :: omp_in_parallel
+ logical (4) :: omp_in_parallel
end function omp_in_parallel
end interface
interface
function omp_test_lock (lock)
use omp_lib_kinds
- logical (omp_logical_kind) :: omp_test_lock
+ logical (4) :: omp_test_lock
integer (omp_lock_kind), intent (inout) :: lock
end function omp_test_lock
end interface
interface
function omp_get_max_threads ()
use omp_lib_kinds
- integer (omp_integer_kind) :: omp_get_max_threads
+ integer (4) :: omp_get_max_threads
end function omp_get_max_threads
end interface
interface
function omp_get_num_procs ()
use omp_lib_kinds
- integer (omp_integer_kind) :: omp_get_num_procs
+ integer (4) :: omp_get_num_procs
end function omp_get_num_procs
end interface
interface
function omp_get_num_threads ()
use omp_lib_kinds
- integer (omp_integer_kind) :: omp_get_num_threads
+ integer (4) :: omp_get_num_threads
end function omp_get_num_threads
end interface
interface
function omp_get_thread_num ()
use omp_lib_kinds
- integer (omp_integer_kind) :: omp_get_thread_num
+ integer (4) :: omp_get_thread_num
end function omp_get_thread_num
end interface
interface
function omp_test_nest_lock (lock)
use omp_lib_kinds
- integer (omp_integer_kind) :: omp_test_nest_lock
+ integer (4) :: omp_test_nest_lock
integer (omp_nest_lock_kind), intent (inout) :: lock
end function omp_test_nest_lock
end interface
interface
function omp_get_thread_limit ()
use omp_lib_kinds
- integer (omp_integer_kind) :: omp_get_thread_limit
+ integer (4) :: omp_get_thread_limit
end function omp_get_thread_limit
end interface
interface
function omp_get_max_active_levels ()
use omp_lib_kinds
- integer (omp_integer_kind) :: omp_get_max_active_levels
+ integer (4) :: omp_get_max_active_levels
end function omp_get_max_active_levels
end interface
interface
function omp_get_level ()
use omp_lib_kinds
- integer (omp_integer_kind) :: omp_get_level
+ integer (4) :: omp_get_level
end function omp_get_level
end interface
function omp_get_ancestor_thread_num (level)
use omp_lib_kinds
integer (4), intent (in) :: level
- integer (omp_integer_kind) :: omp_get_ancestor_thread_num
+ integer (4) :: omp_get_ancestor_thread_num
end function omp_get_ancestor_thread_num
function omp_get_ancestor_thread_num_8 (level)
use omp_lib_kinds
integer (8), intent (in) :: level
- integer (omp_integer_kind) :: omp_get_ancestor_thread_num_8
+ integer (4) :: omp_get_ancestor_thread_num_8
end function omp_get_ancestor_thread_num_8
end interface
function omp_get_team_size (level)
use omp_lib_kinds
integer (4), intent (in) :: level
- integer (omp_integer_kind) :: omp_get_team_size
+ integer (4) :: omp_get_team_size
end function omp_get_team_size
function omp_get_team_size_8 (level)
use omp_lib_kinds
integer (8), intent (in) :: level
- integer (omp_integer_kind) :: omp_get_team_size_8
+ integer (4) :: omp_get_team_size_8
end function omp_get_team_size_8
end interface
interface
function omp_get_active_level ()
use omp_lib_kinds
- integer (omp_integer_kind) :: omp_get_active_level
+ integer (4) :: omp_get_active_level
end function omp_get_active_level
end interface
+ interface
+ function omp_in_final ()
+ use omp_lib_kinds
+ logical (4) :: omp_in_final
+ end function omp_in_final
+ end interface
+
end module omp_lib
-! Copyright (C) 2005, 2007, 2008, 2009 Free Software Foundation, Inc.
+! Copyright (C) 2005, 2007, 2008, 2009, 2011 Free Software Foundation, Inc.
! Contributed by Jakub Jelinek <jakub@redhat.com>.
! This file is part of the GNU OpenMP Library (libgomp).
! <http://www.gnu.org/licenses/>.
integer omp_lock_kind, omp_nest_lock_kind, openmp_version
- integer omp_sched_kind, omp_sched_static, omp_sched_dynamic
- integer omp_sched_guided, omp_sched_auto
parameter (omp_lock_kind = @OMP_LOCK_KIND@)
parameter (omp_nest_lock_kind = @OMP_NEST_LOCK_KIND@)
+ integer omp_sched_kind
parameter (omp_sched_kind = 4)
+ integer (omp_sched_kind) omp_sched_static, omp_sched_dynamic
+ integer (omp_sched_kind) omp_sched_guided, omp_sched_auto
parameter (omp_sched_static = 1)
parameter (omp_sched_dynamic = 2)
parameter (omp_sched_guided = 3)
parameter (omp_sched_auto = 4)
- parameter (openmp_version = 200805)
+ parameter (openmp_version = 201107)
external omp_init_lock, omp_init_nest_lock
external omp_destroy_lock, omp_destroy_nest_lock
integer(4) omp_get_thread_limit, omp_get_max_active_levels
integer(4) omp_get_level, omp_get_ancestor_thread_num
integer(4) omp_get_team_size, omp_get_active_level
+
+ external omp_in_final
+ logical(4) omp_in_final
-/* Copyright (C) 2007, 2008, 2009 Free Software Foundation, Inc.
+/* Copyright (C) 2007, 2008, 2009, 2011 Free Software Foundation, Inc.
Contributed by Richard Henderson <rth@redhat.com>.
This file is part of the GNU OpenMP Library (libgomp).
task->kind = GOMP_TASK_IMPLICIT;
task->in_taskwait = false;
task->in_tied_task = false;
+ task->final_task = false;
task->children = NULL;
gomp_sem_init (&task->taskwait_sem, 0);
}
void
GOMP_task (void (*fn) (void *), void *data, void (*cpyfn) (void *, void *),
- long arg_size, long arg_align, bool if_clause,
- unsigned flags __attribute__((unused)))
+ long arg_size, long arg_align, bool if_clause, unsigned flags)
{
struct gomp_thread *thr = gomp_thread ();
struct gomp_team *team = thr->ts.team;
#endif
if (!if_clause || team == NULL
+ || (thr->task && thr->task->final_task)
|| team->task_count > 64 * team->nthreads)
{
struct gomp_task task;
gomp_init_task (&task, thr->task, gomp_icv (false));
task.kind = GOMP_TASK_IFFALSE;
+ task.final_task = (thr->task && thr->task->final_task) || (flags & 2);
if (thr->task)
task.in_tied_task = thr->task->in_tied_task;
thr->task = &task;
task->fn = fn;
task->fn_data = arg;
task->in_tied_task = true;
+ task->final_task = (flags & 2) >> 1;
gomp_mutex_lock (&team->task_lock);
if (parent->children)
{
}
}
}
+
+/* Called when encountering a taskyield directive. */
+
+void
+GOMP_taskyield (void)
+{
+ /* Nothing at the moment. */
+}
+
+int
+omp_in_final (void)
+{
+ struct gomp_thread *thr = gomp_thread ();
+ return thr->task && thr->task->final_task;
+}
+
+ialias (omp_in_final)
-/* Copyright (C) 2005, 2006, 2007, 2008, 2009 Free Software Foundation, Inc.
+/* Copyright (C) 2005, 2006, 2007, 2008, 2009, 2011
+ Free Software Foundation, Inc.
Contributed by Richard Henderson <rth@redhat.com>.
This file is part of the GNU OpenMP Library (libgomp).
struct gomp_thread_pool *pool;
unsigned i, n, old_threads_used = 0;
pthread_attr_t thread_attr, *attr;
+ unsigned long nthreads_var;
thr = gomp_thread ();
nested = thr->ts.team != NULL;
#endif
thr->ts.static_trip = 0;
thr->task = &team->implicit_task[0];
+ nthreads_var = icv->nthreads_var;
+ if (__builtin_expect (gomp_nthreads_var_list != NULL, 0)
+ && thr->ts.level < gomp_nthreads_var_list_len)
+ nthreads_var = gomp_nthreads_var_list[thr->ts.level];
gomp_init_task (thr->task, task, icv);
+ team->implicit_task[0].icv.nthreads_var = nthreads_var;
if (nthreads == 1)
return;
nthr->ts.static_trip = 0;
nthr->task = &team->implicit_task[i];
gomp_init_task (nthr->task, task, icv);
+ team->implicit_task[i].icv.nthreads_var = nthreads_var;
nthr->fn = fn;
nthr->data = data;
team->ordered_release[i] = &nthr->release;
start_data->ts.static_trip = 0;
start_data->task = &team->implicit_task[i];
gomp_init_task (start_data->task, task, icv);
+ team->implicit_task[i].icv.nthreads_var = nthreads_var;
start_data->thread_pool = pool;
start_data->nested = nested;
--- /dev/null
+// { dg-do run }
+
+extern "C" void abort (void);
+int x = 6;
+float y;
+
+int
+main (void)
+{
+ int v;
+ float f;
+ #pragma omp atomic read
+ v = x;
+ if (v != 6)
+ abort ();
+ #pragma omp atomic write
+ x = 17;
+ #pragma omp atomic read
+ v = x;
+ if (v != 17)
+ abort ();
+ #pragma omp atomic update
+ x++;
+ #pragma omp atomic read
+ v = x;
+ if (v != 18)
+ abort ();
+ #pragma omp atomic capture
+ v = x++;
+ if (v != 18)
+ abort ();
+ #pragma omp atomic read
+ v = x;
+ if (v != 19)
+ abort ();
+ #pragma omp atomic capture
+ v = ++x;
+ if (v != 20)
+ abort ();
+ #pragma omp atomic read
+ v = x;
+ if (v != 20)
+ abort ();
+ #pragma omp atomic capture
+ { v = x; x *= 3; }
+ if (v != 20)
+ abort ();
+ #pragma omp atomic read
+ v = x;
+ if (v != 60)
+ abort ();
+ #pragma omp atomic capture
+ {
+ x |= 2;
+ v = x;
+ }
+ if (v != 62)
+ abort ();
+ #pragma omp atomic read
+ v = x;
+ if (v != 62)
+ abort ();
+ #pragma omp atomic capture
+ { v = x; x++; }
+ if (v != 62)
+ abort ();
+ #pragma omp atomic capture
+ { v = x; ++x; }
+ if (v != 63)
+ abort ();
+ #pragma omp atomic capture
+ {
+ ++x;
+ v = x;
+ }
+ if (v != 65)
+ abort ();
+#pragma omp atomic capture
+{x++;v=x;}if (v != 66)
+ abort ();
+ #pragma omp atomic read
+ v = x;
+ if (v != 66)
+ abort ();
+ #pragma omp atomic capture
+ { v = x; x--; }
+ if (v != 66)
+ abort ();
+ #pragma omp atomic capture
+ { v = x; --x; }
+ if (v != 65)
+ abort ();
+ #pragma omp atomic capture
+ {
+ --x;
+ v = x;
+ }
+ if (v != 63)
+ abort ();
+ #pragma omp atomic capture
+ { x--; v = x; } if (v != 62)
+ abort ();
+ #pragma omp atomic read
+ v = x;
+ if (v != 62)
+ abort ();
+ #pragma omp atomic write
+ y = 17.5f;
+ #pragma omp atomic read
+ f = y;
+ if (f != 17.5)
+ abort ();
+ #pragma omp atomic update
+ y *= 2.0f;
+ #pragma omp atomic read
+ f = y;
+ if (y != 35.0)
+ abort ();
+ #pragma omp atomic capture
+ f = y *= 2.0f;
+ if (f != 70.0)
+ abort ();
+ #pragma omp atomic capture
+ f = y++;
+ if (f != 70.0)
+ abort ();
+ #pragma omp atomic read
+ f = y;
+ if (f != 71.0)
+ abort ();
+ #pragma omp atomic capture
+ f = --y;
+ if (f != 70.0)
+ abort ();
+ #pragma omp atomic read
+ f = y;
+ if (f != 70.0)
+ abort ();
+ #pragma omp atomic capture
+ { f = y; y /= 2.0f; }
+ if (f != 70.0)
+ abort ();
+ #pragma omp atomic read
+ f = y;
+ if (f != 35.0)
+ abort ();
+ #pragma omp atomic capture
+ { y /= 2.0f; f = y; }
+ if (f != 17.5)
+ abort ();
+ #pragma omp atomic read
+ f = y;
+ if (f != 17.5)
+ abort ();
+ return 0;
+}
--- /dev/null
+// { dg-do run }
+
+extern "C" void abort (void);
+bool v, x1, x2, x3, x4, x5, x6;
+
+void
+foo ()
+{
+ #pragma omp atomic capture
+ v = ++x1;
+ if (!v)
+ abort ();
+ #pragma omp atomic capture
+ v = x2++;
+ if (v)
+ abort ();
+ #pragma omp atomic read
+ v = x3;
+ if (!v)
+ abort ();
+ #pragma omp atomic read
+ v = x4;
+ if (!v)
+ abort ();
+ #pragma omp atomic capture
+ { v = x5; x5 |= 1; }
+ if (v)
+ abort ();
+ #pragma omp atomic capture
+ { x6 |= 1; v = x6; }
+ if (!v)
+ abort ();
+}
+
+void
+bar ()
+{
+ #pragma omp atomic write
+ x1 = false;
+ #pragma omp atomic write
+ x2 = false;
+ #pragma omp atomic capture
+ { ++x1; v = x1; }
+ if (!v)
+ abort ();
+ #pragma omp atomic capture
+ { v = x2; x2++; }
+ if (v)
+ abort ();
+ #pragma omp atomic write
+ x1 = false;
+ #pragma omp atomic write
+ x2 = false;
+ #pragma omp atomic capture
+ { x1++; v = x1; }
+ if (!v)
+ abort ();
+ #pragma omp atomic capture
+ { v = x2; ++x2; }
+ if (v)
+ abort ();
+}
+
+int
+main ()
+{
+ #pragma omp atomic write
+ x3 = true;
+ #pragma omp atomic write
+ x4 = true;
+ foo ();
+ bar ();
+ return 0;
+}
--- /dev/null
+// { dg-do run }
+
+extern "C" void abort (void);
+template <typename T, typename T2>
+int
+foo (void)
+{
+ extern T x;
+ extern T2 y;
+ T v;
+ T2 f;
+ #pragma omp atomic read
+ v = x;
+ if (v != 6)
+ abort ();
+ #pragma omp atomic write
+ x = 17;
+ #pragma omp atomic read
+ v = x;
+ if (v != 17)
+ abort ();
+ #pragma omp atomic update
+ x++;
+ #pragma omp atomic read
+ v = x;
+ if (v != 18)
+ abort ();
+ #pragma omp atomic capture
+ v = x++;
+ if (v != 18)
+ abort ();
+ #pragma omp atomic read
+ v = x;
+ if (v != 19)
+ abort ();
+ #pragma omp atomic capture
+ v = ++x;
+ if (v != 20)
+ abort ();
+ #pragma omp atomic read
+ v = x;
+ if (v != 20)
+ abort ();
+ #pragma omp atomic capture
+ { v = x; x *= 3; }
+ if (v != 20)
+ abort ();
+ #pragma omp atomic read
+ v = x;
+ if (v != 60)
+ abort ();
+ #pragma omp atomic capture
+ {
+ x |= 2;
+ v = x;
+ }
+ if (v != 62)
+ abort ();
+ #pragma omp atomic read
+ v = x;
+ if (v != 62)
+ abort ();
+ #pragma omp atomic capture
+ { v = x; x++; }
+ if (v != 62)
+ abort ();
+ #pragma omp atomic capture
+ { v = x; ++x; }
+ if (v != 63)
+ abort ();
+ #pragma omp atomic capture
+ {
+ ++x;
+ v = x;
+ }
+ if (v != 65)
+ abort ();
+#pragma omp atomic capture
+{x++;v=x;}if (v != 66)
+ abort ();
+ #pragma omp atomic read
+ v = x;
+ if (v != 66)
+ abort ();
+ #pragma omp atomic capture
+ { v = x; x--; }
+ if (v != 66)
+ abort ();
+ #pragma omp atomic capture
+ { v = x; --x; }
+ if (v != 65)
+ abort ();
+ #pragma omp atomic capture
+ {
+ --x;
+ v = x;
+ }
+ if (v != 63)
+ abort ();
+ #pragma omp atomic capture
+ { x--; v = x; } if (v != 62)
+ abort ();
+ #pragma omp atomic read
+ v = x;
+ if (v != 62)
+ abort ();
+ #pragma omp atomic write
+ y = 17.5f;
+ #pragma omp atomic read
+ f = y;
+ if (f != 17.5)
+ abort ();
+ #pragma omp atomic update
+ y *= 2.0f;
+ #pragma omp atomic read
+ f = y;
+ if (y != 35.0)
+ abort ();
+ #pragma omp atomic capture
+ f = y *= 2.0f;
+ if (f != 70.0)
+ abort ();
+ #pragma omp atomic capture
+ f = y++;
+ if (f != 70.0)
+ abort ();
+ #pragma omp atomic read
+ f = y;
+ if (f != 71.0)
+ abort ();
+ #pragma omp atomic capture
+ f = --y;
+ if (f != 70.0)
+ abort ();
+ #pragma omp atomic read
+ f = y;
+ if (f != 70.0)
+ abort ();
+ #pragma omp atomic capture
+ { f = y; y /= 2.0f; }
+ if (f != 70.0)
+ abort ();
+ #pragma omp atomic read
+ f = y;
+ if (f != 35.0)
+ abort ();
+ #pragma omp atomic capture
+ { y /= 2.0f; f = y; }
+ if (f != 17.5)
+ abort ();
+ #pragma omp atomic read
+ f = y;
+ if (f != 17.5)
+ abort ();
+ return 0;
+}
+
+int x = 6;
+float y;
+
+int
+main ()
+{
+ foo <int, float> ();
+ return 0;
+}
--- /dev/null
+// { dg-do run }
+
+extern "C" void abort (void);
+
+template <typename T>
+void
+foo ()
+{
+ extern T v, x1, x2, x3, x4, x5, x6;
+ #pragma omp atomic capture
+ v = ++x1;
+ if (!v)
+ abort ();
+ #pragma omp atomic capture
+ v = x2++;
+ if (v)
+ abort ();
+ #pragma omp atomic read
+ v = x3;
+ if (!v)
+ abort ();
+ #pragma omp atomic read
+ v = x4;
+ if (!v)
+ abort ();
+ #pragma omp atomic capture
+ { v = x5; x5 |= 1; }
+ if (v)
+ abort ();
+ #pragma omp atomic capture
+ { x6 |= 1; v = x6; }
+ if (!v)
+ abort ();
+}
+
+template <typename T>
+void
+bar ()
+{
+ extern T v, x1, x2;
+ #pragma omp atomic write
+ x1 = false;
+ #pragma omp atomic write
+ x2 = false;
+ #pragma omp atomic capture
+ { ++x1; v = x1; }
+ if (!v)
+ abort ();
+ #pragma omp atomic capture
+ { v = x2; x2++; }
+ if (v)
+ abort ();
+ #pragma omp atomic write
+ x1 = false;
+ #pragma omp atomic write
+ x2 = false;
+ #pragma omp atomic capture
+ { x1++; v = x1; }
+ if (!v)
+ abort ();
+ #pragma omp atomic capture
+ { v = x2; ++x2; }
+ if (v)
+ abort ();
+}
+
+bool v, x1, x2, x3, x4, x5, x6;
+
+int
+main ()
+{
+ #pragma omp atomic write
+ x3 = true;
+ #pragma omp atomic write
+ x4 = true;
+ foo <bool> ();
+ bar <bool> ();
+ return 0;
+}
--- /dev/null
+// { dg-do run }
+
+extern "C" void abort (void);
+long long l, m;
+int i, j;
+
+void
+foo (void)
+{
+ #pragma omp atomic read
+ i = l;
+ #pragma omp atomic read
+ m = j;
+ if (i != 77 || m != 88)
+ abort ();
+ #pragma omp atomic write
+ l = 1 + i + 6 * 1;
+ #pragma omp atomic write
+ j = 170 - 170 + m + 1 * 7;
+ #pragma omp atomic capture
+ i = l += 4;
+ #pragma omp atomic capture
+ m = j += 4;
+ if (i != 88 || m != 99)
+ abort ();
+ #pragma omp atomic capture
+ {
+ i = l;
+ l += 4;
+ }
+ #pragma omp atomic capture
+ {
+ m = j;
+ j += 4;
+ }
+ if (i != 88 || m != 99)
+ abort ();
+ #pragma omp atomic capture
+ {
+ l += 4;
+ i = l;
+ }
+ #pragma omp atomic capture
+ {
+ j += 4;
+ m = j;
+ }
+ if (i != 96 || m != 107)
+ abort ();
+}
+
+int
+main ()
+{
+ l = 77;
+ j = 88;
+ foo ();
+}
--- /dev/null
+// { dg-do run }
+
+extern "C" void abort (void);
+
+template <typename S, typename T>
+void
+foo (void)
+{
+ extern S l, m;
+ extern T i, j;
+
+ #pragma omp atomic read
+ i = l;
+ #pragma omp atomic read
+ m = j;
+ if (i != 77 || m != 88)
+ abort ();
+ #pragma omp atomic write
+ l = 1 + i + 6 * 1;
+ #pragma omp atomic write
+ j = 170 - 170 + m + 1 * 7;
+ #pragma omp atomic capture
+ i = l += 4;
+ #pragma omp atomic capture
+ m = j += 4;
+ if (i != 88 || m != 99)
+ abort ();
+ #pragma omp atomic capture
+ {
+ i = l;
+ l += 4;
+ }
+ #pragma omp atomic capture
+ {
+ m = j;
+ j += 4;
+ }
+ if (i != 88 || m != 99)
+ abort ();
+ #pragma omp atomic capture
+ {
+ l += 4;
+ i = l;
+ }
+ #pragma omp atomic capture
+ {
+ j += 4;
+ m = j;
+ }
+ if (i != 96 || m != 107)
+ abort ();
+}
+
+long long l, m;
+int i, j;
+
+int
+main ()
+{
+ l = 77;
+ j = 88;
+ foo <long long, int> ();
+}
--- /dev/null
+// { dg-do run }
+
+extern "C" void abort ();
+int x = 6, cnt;
+
+int
+foo ()
+{
+ return cnt++;
+}
+
+int
+main ()
+{
+ int v, *p;
+ #pragma omp atomic update
+ x = x + 7;
+ #pragma omp atomic
+ x = x + 7 + 6;
+ #pragma omp atomic update
+ x = x + 2 * 3;
+ #pragma omp atomic
+ x = x * (2 - 1);
+ #pragma omp atomic read
+ v = x;
+ if (v != 32)
+ abort ();
+ #pragma omp atomic write
+ x = 0;
+ #pragma omp atomic capture
+ {
+ v = x;
+ x = x | 1 ^ 2;
+ }
+ if (v != 0)
+ abort ();
+ #pragma omp atomic capture
+ {
+ v = x;
+ x = x | 4 | 2;
+ }
+ if (v != 3)
+ abort ();
+ #pragma omp atomic read
+ v = x;
+ if (v != 7)
+ abort ();
+ #pragma omp atomic capture
+ {
+ x = x ^ 6 & 2;
+ v = x;
+ }
+ if (v != 5)
+ abort ();
+ #pragma omp atomic capture
+ { x = x - (6 + 4); v = x; }
+ if (v != -5)
+ abort ();
+ #pragma omp atomic capture
+ { v = x; x = x - (1 | 2); }
+ if (v != -5)
+ abort ();
+ #pragma omp atomic read
+ v = x;
+ if (v != -8)
+ abort ();
+ #pragma omp atomic
+ x = x * -4 / 2;
+ #pragma omp atomic read
+ v = x;
+ if (v != 16)
+ abort ();
+ p = &x;
+ #pragma omp atomic update
+ p[foo (), 0] = p[foo (), 0] - 16;
+ #pragma omp atomic read
+ v = x;
+ if (cnt != 2 || v != 0)
+ abort ();
+ #pragma omp atomic capture
+ {
+ p[foo (), 0] += 6;
+ v = p[foo (), 0];
+ }
+ if (cnt != 4 || v != 6)
+ abort ();
+ #pragma omp atomic capture
+ {
+ v = p[foo (), 0];
+ p[foo (), 0] += 6;
+ }
+ if (cnt != 6 || v != 6)
+ abort ();
+ #pragma omp atomic read
+ v = x;
+ if (v != 12)
+ abort ();
+ #pragma omp atomic capture
+ {
+ p[foo (), 0] = p[foo (), 0] + 6;
+ v = p[foo (), 0];
+ }
+ if (cnt != 9 || v != 18)
+ abort ();
+ #pragma omp atomic capture
+ {
+ v = p[foo (), 0];
+ p[foo (), 0] = p[foo (), 0] + 6;
+ }
+ if (cnt != 12 || v != 18)
+ abort ();
+ #pragma omp atomic read
+ v = x;
+ if (v != 24)
+ abort ();
+ #pragma omp atomic capture
+ { v = p[foo (), 0]; p[foo (), 0]++; }
+ #pragma omp atomic capture
+ { v = p[foo (), 0]; ++p[foo (), 0]; }
+ #pragma omp atomic capture
+ { p[foo (), 0]++; v = p[foo (), 0]; }
+ #pragma omp atomic capture
+ { ++p[foo (), 0]; v = p[foo (), 0]; }
+ if (cnt != 20 || v != 28)
+ abort ();
+ #pragma omp atomic capture
+ { v = p[foo (), 0]; p[foo (), 0]--; }
+ #pragma omp atomic capture
+ { v = p[foo (), 0]; --p[foo (), 0]; }
+ #pragma omp atomic capture
+ { p[foo (), 0]--; v = p[foo (), 0]; }
+ #pragma omp atomic capture
+ { --p[foo (), 0]; v = p[foo (), 0]; }
+ if (cnt != 28 || v != 24)
+ abort ();
+ return 0;
+}
--- /dev/null
+// { dg-do run }
+
+extern "C" void abort ();
+
+int cnt;
+
+int
+foo ()
+{
+ return cnt++;
+}
+
+template <typename T>
+void
+bar ()
+{
+ extern T x;
+ T v, *p;
+ #pragma omp atomic update
+ x = x + 7;
+ #pragma omp atomic
+ x = x + 7 + 6;
+ #pragma omp atomic update
+ x = x + 2 * 3;
+ #pragma omp atomic
+ x = x * (2 - 1);
+ #pragma omp atomic read
+ v = x;
+ if (v != 32)
+ abort ();
+ #pragma omp atomic write
+ x = 0;
+ #pragma omp atomic capture
+ {
+ v = x;
+ x = x | 1 ^ 2;
+ }
+ if (v != 0)
+ abort ();
+ #pragma omp atomic capture
+ {
+ v = x;
+ x = x | 4 | 2;
+ }
+ if (v != 3)
+ abort ();
+ #pragma omp atomic read
+ v = x;
+ if (v != 7)
+ abort ();
+ #pragma omp atomic capture
+ {
+ x = x ^ 6 & 2;
+ v = x;
+ }
+ if (v != 5)
+ abort ();
+ #pragma omp atomic capture
+ { x = x - (6 + 4); v = x; }
+ if (v != -5)
+ abort ();
+ #pragma omp atomic capture
+ { v = x; x = x - (1 | 2); }
+ if (v != -5)
+ abort ();
+ #pragma omp atomic read
+ v = x;
+ if (v != -8)
+ abort ();
+ #pragma omp atomic
+ x = x * -4 / 2;
+ #pragma omp atomic read
+ v = x;
+ if (v != 16)
+ abort ();
+ p = &x;
+ #pragma omp atomic update
+ p[foo (), 0] = p[foo (), 0] - 16;
+ #pragma omp atomic read
+ v = x;
+ if (cnt != 2 || v != 0)
+ abort ();
+ #pragma omp atomic capture
+ {
+ p[foo (), 0] += 6;
+ v = p[foo (), 0];
+ }
+ if (cnt != 4 || v != 6)
+ abort ();
+ #pragma omp atomic capture
+ {
+ v = p[foo (), 0];
+ p[foo (), 0] += 6;
+ }
+ if (cnt != 6 || v != 6)
+ abort ();
+ #pragma omp atomic read
+ v = x;
+ if (v != 12)
+ abort ();
+ #pragma omp atomic capture
+ {
+ p[foo (), 0] = p[foo (), 0] + 6;
+ v = p[foo (), 0];
+ }
+ if (cnt != 9 || v != 18)
+ abort ();
+ #pragma omp atomic capture
+ {
+ v = p[foo (), 0];
+ p[foo (), 0] = p[foo (), 0] + 6;
+ }
+ if (cnt != 12 || v != 18)
+ abort ();
+ #pragma omp atomic read
+ v = x;
+ if (v != 24)
+ abort ();
+ #pragma omp atomic capture
+ { v = p[foo (), 0]; p[foo (), 0]++; }
+ #pragma omp atomic capture
+ { v = p[foo (), 0]; ++p[foo (), 0]; }
+ #pragma omp atomic capture
+ { p[foo (), 0]++; v = p[foo (), 0]; }
+ #pragma omp atomic capture
+ { ++p[foo (), 0]; v = p[foo (), 0]; }
+ if (cnt != 20 || v != 28)
+ abort ();
+ #pragma omp atomic capture
+ { v = p[foo (), 0]; p[foo (), 0]--; }
+ #pragma omp atomic capture
+ { v = p[foo (), 0]; --p[foo (), 0]; }
+ #pragma omp atomic capture
+ { p[foo (), 0]--; v = p[foo (), 0]; }
+ #pragma omp atomic capture
+ { --p[foo (), 0]; v = p[foo (), 0]; }
+ if (cnt != 28 || v != 24)
+ abort ();
+}
+
+int x = 6;
+
+int
+main ()
+{
+ bar <int> ();
+ return 0;
+}
--- /dev/null
+// { dg-do run }
+
+extern "C" void abort (void);
+
+template <typename I, typename F>
+void
+foo ()
+{
+ I j = -10000;
+ F f = 1024.0;
+ int i;
+ #pragma omp parallel for reduction (min:f) reduction (max:j)
+ for (i = 0; i < 4; i++)
+ switch (i)
+ {
+ case 0:
+ if (j < -16) j = -16; break;
+ case 1:
+ if (f > -2.0) f = -2.0; break;
+ case 2:
+ if (j < 8) j = 8; if (f > 9.0) f = 9.0; break;
+ case 3:
+ break;
+ }
+ if (j != 8 || f != -2.0)
+ abort ();
+}
+
+int
+main ()
+{
+ int j = -10000;
+ float f = 1024.0;
+ int i;
+ #pragma omp parallel for reduction (min:f) reduction (max:j)
+ for (i = 0; i < 4; i++)
+ switch (i)
+ {
+ case 0:
+ if (j < -16) j = -16; break;
+ case 1:
+ if (f > -2.0) f = -2.0; break;
+ case 2:
+ if (j < 8) j = 8; if (f > 9.0) f = 9.0; break;
+ case 3:
+ break;
+ }
+ if (j != 8 || f != -2.0)
+ abort ();
+ foo <int, float> ();
+ foo <long, double> ();
+ foo <long long, long double> ();
+ return 0;
+}
--- /dev/null
+// { dg-do run }
+
+#include <omp.h>
+#include <cstdlib>
+
+int err;
+
+int
+main ()
+{
+ int e;
+#pragma omp parallel shared(err)
+ {
+ if (omp_in_final ())
+ #pragma omp atomic write
+ err = 1;
+ #pragma omp task if (0) shared(err)
+ {
+ if (omp_in_final ())
+ #pragma omp atomic write
+ err = 1;
+ #pragma omp task if (0) shared(err)
+ if (omp_in_final ())
+ #pragma omp atomic write
+ err = 1;
+ }
+ #pragma omp task final (1) shared(err)
+ {
+ if (!omp_in_final ())
+ #pragma omp atomic write
+ err = 1;
+ #pragma omp taskyield
+ #pragma omp taskwait
+ #pragma omp task shared(err)
+ if (!omp_in_final ())
+ #pragma omp atomic write
+ err = 1;
+ }
+ }
+ #pragma omp atomic read
+ e = err;
+ if (e)
+ abort ();
+}
--- /dev/null
+/* { dg-do run } */
+
+extern void abort (void);
+int x = 6;
+float y;
+
+int
+main (void)
+{
+ int v;
+ float f;
+ #pragma omp atomic read
+ v = x;
+ if (v != 6)
+ abort ();
+ #pragma omp atomic write
+ x = 17;
+ #pragma omp atomic read
+ v = x;
+ if (v != 17)
+ abort ();
+ #pragma omp atomic update
+ x++;
+ #pragma omp atomic read
+ v = x;
+ if (v != 18)
+ abort ();
+ #pragma omp atomic capture
+ v = x++;
+ if (v != 18)
+ abort ();
+ #pragma omp atomic read
+ v = x;
+ if (v != 19)
+ abort ();
+ #pragma omp atomic capture
+ v = ++x;
+ if (v != 20)
+ abort ();
+ #pragma omp atomic read
+ v = x;
+ if (v != 20)
+ abort ();
+ #pragma omp atomic capture
+ { v = x; x *= 3; }
+ if (v != 20)
+ abort ();
+ #pragma omp atomic read
+ v = x;
+ if (v != 60)
+ abort ();
+ #pragma omp atomic capture
+ {
+ x |= 2;
+ v = x;
+ }
+ if (v != 62)
+ abort ();
+ #pragma omp atomic read
+ v = x;
+ if (v != 62)
+ abort ();
+ #pragma omp atomic capture
+ { v = x; x++; }
+ if (v != 62)
+ abort ();
+ #pragma omp atomic capture
+ { v = x; ++x; }
+ if (v != 63)
+ abort ();
+ #pragma omp atomic capture
+ {
+ ++x;
+ v = x;
+ }
+ if (v != 65)
+ abort ();
+#pragma omp atomic capture
+{x++;v=x;}if (v != 66)
+ abort ();
+ #pragma omp atomic read
+ v = x;
+ if (v != 66)
+ abort ();
+ #pragma omp atomic capture
+ { v = x; x--; }
+ if (v != 66)
+ abort ();
+ #pragma omp atomic capture
+ { v = x; --x; }
+ if (v != 65)
+ abort ();
+ #pragma omp atomic capture
+ {
+ --x;
+ v = x;
+ }
+ if (v != 63)
+ abort ();
+ #pragma omp atomic capture
+ { x--; v = x; } if (v != 62)
+ abort ();
+ #pragma omp atomic read
+ v = x;
+ if (v != 62)
+ abort ();
+ #pragma omp atomic write
+ y = 17.5f;
+ #pragma omp atomic read
+ f = y;
+ if (f != 17.5)
+ abort ();
+ #pragma omp atomic update
+ y *= 2.0f;
+ #pragma omp atomic read
+ f = y;
+ if (y != 35.0)
+ abort ();
+ #pragma omp atomic capture
+ f = y *= 2.0f;
+ if (f != 70.0)
+ abort ();
+ #pragma omp atomic capture
+ f = y++;
+ if (f != 70.0)
+ abort ();
+ #pragma omp atomic read
+ f = y;
+ if (f != 71.0)
+ abort ();
+ #pragma omp atomic capture
+ f = --y;
+ if (f != 70.0)
+ abort ();
+ #pragma omp atomic read
+ f = y;
+ if (f != 70.0)
+ abort ();
+ #pragma omp atomic capture
+ { f = y; y /= 2.0f; }
+ if (f != 70.0)
+ abort ();
+ #pragma omp atomic read
+ f = y;
+ if (f != 35.0)
+ abort ();
+ #pragma omp atomic capture
+ { y /= 2.0f; f = y; }
+ if (f != 17.5)
+ abort ();
+ #pragma omp atomic read
+ f = y;
+ if (f != 17.5)
+ abort ();
+ return 0;
+}
--- /dev/null
+/* { dg-do run } */
+
+extern void abort (void);
+_Bool v, x1, x2, x3, x4, x5, x6;
+
+void
+foo (void)
+{
+ #pragma omp atomic capture
+ v = ++x1;
+ if (!v)
+ abort ();
+ #pragma omp atomic capture
+ v = x2++;
+ if (v)
+ abort ();
+ #pragma omp atomic capture
+ v = --x3;
+ if (v)
+ abort ();
+ #pragma omp atomic capture
+ v = x4--;
+ if (!v)
+ abort ();
+ #pragma omp atomic capture
+ { v = x5; x5 |= 1; }
+ if (v)
+ abort ();
+ #pragma omp atomic capture
+ { x6 |= 1; v = x6; }
+ if (!v)
+ abort ();
+}
+
+void
+bar (void)
+{
+ #pragma omp atomic write
+ x1 = 0;
+ #pragma omp atomic write
+ x2 = 0;
+ #pragma omp atomic write
+ x3 = 1;
+ #pragma omp atomic write
+ x4 = 1;
+ #pragma omp atomic capture
+ { ++x1; v = x1; }
+ if (!v)
+ abort ();
+ #pragma omp atomic capture
+ { v = x2; x2++; }
+ if (v)
+ abort ();
+ #pragma omp atomic capture
+ { --x3; v = x3; }
+ if (v)
+ abort ();
+ #pragma omp atomic capture
+ { v = x4; x4--; }
+ if (!v)
+ abort ();
+ #pragma omp atomic write
+ x1 = 0;
+ #pragma omp atomic write
+ x2 = 0;
+ #pragma omp atomic write
+ x3 = 1;
+ #pragma omp atomic write
+ x4 = 1;
+ #pragma omp atomic capture
+ { x1++; v = x1; }
+ if (!v)
+ abort ();
+ #pragma omp atomic capture
+ { v = x2; ++x2; }
+ if (v)
+ abort ();
+ #pragma omp atomic capture
+ { x3--; v = x3; }
+ if (v)
+ abort ();
+ #pragma omp atomic capture
+ { v = x4; --x4; }
+ if (!v)
+ abort ();
+}
+
+int
+main ()
+{
+ #pragma omp atomic write
+ x3 = 1;
+ #pragma omp atomic write
+ x4 = 1;
+ foo ();
+ bar ();
+ return 0;
+}
--- /dev/null
+/* { dg-do run } */
+
+extern void abort (void);
+long long l, m;
+int i, j;
+
+void
+foo (void)
+{
+ #pragma omp atomic read
+ i = l;
+ #pragma omp atomic read
+ m = j;
+ if (i != 77 || m != 88)
+ abort ();
+ #pragma omp atomic write
+ l = 1 + i + 6 * 1;
+ #pragma omp atomic write
+ j = 170 - 170 + m + 1 * 7;
+ #pragma omp atomic capture
+ i = l += 4;
+ #pragma omp atomic capture
+ m = j += 4;
+ if (i != 88 || m != 99)
+ abort ();
+ #pragma omp atomic capture
+ {
+ i = l;
+ l += 4;
+ }
+ #pragma omp atomic capture
+ {
+ m = j;
+ j += 4;
+ }
+ if (i != 88 || m != 99)
+ abort ();
+ #pragma omp atomic capture
+ {
+ l += 4;
+ i = l;
+ }
+ #pragma omp atomic capture
+ {
+ j += 4;
+ m = j;
+ }
+ if (i != 96 || m != 107)
+ abort ();
+}
+
+int
+main ()
+{
+ l = 77;
+ j = 88;
+ foo ();
+ return 0;
+}
--- /dev/null
+/* { dg-do run } */
+
+extern void abort (void);
+int x = 6, cnt;
+
+int
+foo (void)
+{
+ return cnt++;
+}
+
+int
+main ()
+{
+ int v, *p;
+ #pragma omp atomic update
+ x = x + 7;
+ #pragma omp atomic
+ x = x + 7 + 6;
+ #pragma omp atomic update
+ x = x + 2 * 3;
+ #pragma omp atomic
+ x = x * (2 - 1);
+ #pragma omp atomic read
+ v = x;
+ if (v != 32)
+ abort ();
+ #pragma omp atomic write
+ x = 0;
+ #pragma omp atomic capture
+ {
+ v = x;
+ x = x | 1 ^ 2;
+ }
+ if (v != 0)
+ abort ();
+ #pragma omp atomic capture
+ {
+ v = x;
+ x = x | 4 | 2;
+ }
+ if (v != 3)
+ abort ();
+ #pragma omp atomic read
+ v = x;
+ if (v != 7)
+ abort ();
+ #pragma omp atomic capture
+ {
+ x = x ^ 6 & 2;
+ v = x;
+ }
+ if (v != 5)
+ abort ();
+ #pragma omp atomic capture
+ { x = x - (6 + 4); v = x; }
+ if (v != -5)
+ abort ();
+ #pragma omp atomic capture
+ { v = x; x = x - (1 | 2); }
+ if (v != -5)
+ abort ();
+ #pragma omp atomic read
+ v = x;
+ if (v != -8)
+ abort ();
+ #pragma omp atomic
+ x = x * -4 / 2;
+ #pragma omp atomic read
+ v = x;
+ if (v != 16)
+ abort ();
+ p = &x;
+ #pragma omp atomic update
+ p[foo (), 0] = p[foo (), 0] - 16;
+ #pragma omp atomic read
+ v = x;
+ if (cnt != 2 || v != 0)
+ abort ();
+ #pragma omp atomic capture
+ {
+ p[foo (), 0] += 6;
+ v = p[foo (), 0];
+ }
+ if (cnt != 4 || v != 6)
+ abort ();
+ #pragma omp atomic capture
+ {
+ v = p[foo (), 0];
+ p[foo (), 0] += 6;
+ }
+ if (cnt != 6 || v != 6)
+ abort ();
+ #pragma omp atomic read
+ v = x;
+ if (v != 12)
+ abort ();
+ #pragma omp atomic capture
+ {
+ p[foo (), 0] = p[foo (), 0] + 6;
+ v = p[foo (), 0];
+ }
+ if (cnt != 9 || v != 18)
+ abort ();
+ #pragma omp atomic capture
+ {
+ v = p[foo (), 0];
+ p[foo (), 0] = p[foo (), 0] + 6;
+ }
+ if (cnt != 12 || v != 18)
+ abort ();
+ #pragma omp atomic read
+ v = x;
+ if (v != 24)
+ abort ();
+ #pragma omp atomic capture
+ { v = p[foo (), 0]; p[foo (), 0]++; }
+ #pragma omp atomic capture
+ { v = p[foo (), 0]; ++p[foo (), 0]; }
+ #pragma omp atomic capture
+ { p[foo (), 0]++; v = p[foo (), 0]; }
+ #pragma omp atomic capture
+ { ++p[foo (), 0]; v = p[foo (), 0]; }
+ if (cnt != 20 || v != 28)
+ abort ();
+ #pragma omp atomic capture
+ { v = p[foo (), 0]; p[foo (), 0]--; }
+ #pragma omp atomic capture
+ { v = p[foo (), 0]; --p[foo (), 0]; }
+ #pragma omp atomic capture
+ { p[foo (), 0]--; v = p[foo (), 0]; }
+ #pragma omp atomic capture
+ { --p[foo (), 0]; v = p[foo (), 0]; }
+ if (cnt != 28 || v != 24)
+ abort ();
+ return 0;
+}
--- /dev/null
+/* { dg-do run } */
+
+extern void abort (void);
+int j;
+float f;
+
+int
+main ()
+{
+ j = -10000;
+ f = 1024.0;
+ int i;
+ #pragma omp parallel for reduction (min:f) reduction (max:j)
+ for (i = 0; i < 4; i++)
+ switch (i)
+ {
+ case 0:
+ if (j < -16) j = -16; break;
+ case 1:
+ if (f > -2.0) f = -2.0; break;
+ case 2:
+ if (j < 8) j = 8; if (f > 9.0) f = 9.0; break;
+ case 3:
+ break;
+ }
+ if (j != 8 || f != -2.0)
+ abort ();
+ return 0;
+}
--- /dev/null
+/* { dg-do run } */
+
+#include <omp.h>
+#include <stdlib.h>
+
+int err;
+
+int
+main ()
+{
+ int e;
+#pragma omp parallel shared(err)
+ {
+ if (omp_in_final ())
+ #pragma omp atomic write
+ err = 1;
+ #pragma omp task if (0) shared(err)
+ {
+ if (omp_in_final ())
+ #pragma omp atomic write
+ err = 1;
+ #pragma omp task if (0) shared(err)
+ if (omp_in_final ())
+ #pragma omp atomic write
+ err = 1;
+ }
+ #pragma omp task final (1) shared(err)
+ {
+ if (!omp_in_final ())
+ #pragma omp atomic write
+ err = 1;
+ #pragma omp taskyield
+ #pragma omp taskwait
+ #pragma omp task shared(err)
+ if (!omp_in_final ())
+ #pragma omp atomic write
+ err = 1;
+ }
+ }
+ #pragma omp atomic read
+ e = err;
+ if (e)
+ abort ();
+ return 0;
+}
--- /dev/null
+! { dg-do run }
+
+ integer, allocatable :: a(:)
+ logical :: l
+ l = .false.
+!$omp parallel firstprivate (a) reduction (.or.:l)
+ l = allocated (a)
+ allocate (a(10))
+ l = l .or. .not. allocated (a)
+ a = 10
+ if (any (a .ne. 10)) l = .true.
+ deallocate (a)
+ l = l .or. allocated (a)
+!$omp end parallel
+ if (l) call abort
+end
--- /dev/null
+! { dg-do run }
+! { dg-require-effective-target tls_runtime }
+!$ use omp_lib
+
+ integer, save, allocatable :: a(:, :)
+ logical :: l
+!$omp threadprivate (a)
+ if (allocated (a)) call abort
+ l = .false.
+!$omp parallel copyin (a) num_threads (4) reduction(.or.:l)
+ l = l.or.allocated (a)
+!$omp end parallel
+ if (l.or.allocated (a)) call abort
+end
--- /dev/null
+! { dg-do run }
+! { dg-options "-fopenmp -fcray-pointer" }
+
+ use omp_lib
+ integer :: a, b, c, i, p
+ logical :: l
+ pointer (ip, p)
+ a = 1
+ b = 2
+ c = 3
+ l = .false.
+ ip = loc (a)
+
+!$omp parallel num_threads (2) reduction (.or.:l) firstprivate (ip)
+ l = p .ne. 1
+ ip = loc (b)
+ if (omp_get_thread_num () .eq. 1) ip = loc (c)
+ l = l .or. (p .ne. (2 + omp_get_thread_num ()))
+!$omp end parallel
+
+ if (l) call abort
+
+ l = .false.
+ ip = loc (a)
+!$omp parallel do num_threads (2) reduction (.or.:l) &
+!$omp & firstprivate (ip) lastprivate (ip)
+ do i = 0, 1
+ l = l .or. (p .ne. 1)
+ ip = loc (b)
+ if (i .eq. 1) ip = loc (c)
+ l = l .or. (p .ne. (2 + i))
+ end do
+
+ if (l) call abort
+ if (p .ne. 3) call abort
+end
--- /dev/null
+! { dg-do run }
+ integer (kind = 4) :: a, a2
+ integer (kind = 2) :: b, b2
+ real :: c, f
+ double precision :: d, d2, c2
+ integer, dimension (10) :: e
+!$omp atomic write
+ a = 1
+!$omp atomic write
+ b = 2
+!$omp end atomic
+!$omp atomic write
+ c = 3
+!$omp atomic write
+ d = 1 + 2 + 3 - 2
+ e = 5
+!$omp atomic write
+ f = 6
+!$omp end atomic
+!$omp atomic
+ a = a + 4
+!$omp end atomic
+!$omp atomic update
+ b = 4 - b
+!$omp atomic
+ c = c * 2
+!$omp atomic update
+ d = 2 / d
+!$omp end atomic
+!$omp atomic read
+ a2 = a
+!$omp atomic read
+ b2 = b
+!$omp end atomic
+!$omp atomic read
+ c2 = c
+!$omp atomic read
+ d2 = d
+ if (a2 .ne. 5 .or. b2 .ne. 2 .or. c2 .ne. 6 .or. d2 .ne. 0.5) call abort
+!$omp atomic write
+ d = 1.2
+!$omp atomic
+ a = a + c + d
+!$omp atomic
+ b = b - (a + c + d)
+ if (a .ne. 12 .or. b .ne. -17) call abort
+!$omp atomic
+ a = c + d + a
+!$omp atomic
+ b = a + c + d - b
+ if (a .ne. 19 .or. b .ne. 43) call abort
+!$omp atomic
+ b = (a + c + d) - b
+ a = 32
+!$omp atomic
+ a = a / 3.4
+ if (a .ne. 9 .or. b .ne. -16) call abort
+end
--- /dev/null
+! { dg-do run }
+ integer (kind = 4) :: a, a2
+ integer (kind = 2) :: b, b2
+ real :: c
+ double precision :: d, d2, c2
+ integer, dimension (10) :: e
+!$omp atomic write
+ a = 1
+!$omp atomic write
+ b = 2
+!$omp atomic write
+ c = 3
+!$omp atomic write
+ d = 4
+!$omp atomic capture
+ a2 = a
+ a = a + 4
+!$omp end atomic
+!$omp atomic capture
+ b = b - 18
+ b2 = b
+!$omp end atomic
+!$omp atomic capture
+ c2 = c
+ c = 2.0 * c
+!$omp end atomic
+!$omp atomic capture
+ d = d / 2.0
+ d2 = d
+!$omp end atomic
+ if (a2 .ne. 1 .or. b2 .ne. -16 .or. c2 .ne. 3 .or. d2 .ne. 2) call abort
+!$omp atomic read
+ a2 = a
+!$omp atomic read
+ c2 = c
+ if (a2 .ne. 5 .or. b2 .ne. -16 .or. c2 .ne. 6 .or. d2 .ne. 2) call abort
+end
--- /dev/null
+! { dg-do run }
+ integer, pointer :: a, c(:)
+ integer, target :: b, d(10)
+ b = 0
+ a => b
+ d = 0
+ c => d
+ call foo (a, c)
+ b = 0
+ d = 0
+ call bar (a, c)
+contains
+ subroutine foo (a, c)
+ integer, pointer :: a, c(:), b, d(:)
+ integer :: r, r2
+ r = 0
+ !$omp parallel firstprivate (a, c) reduction (+:r)
+ !$omp atomic
+ a = a + 1
+ !$omp atomic
+ c(1) = c(1) + 1
+ r = r + 1
+ !$omp end parallel
+ if (a.ne.r.or.c(1).ne.r) call abort
+ r2 = r
+ b => a
+ d => c
+ r = 0
+ !$omp parallel firstprivate (b, d) reduction (+:r)
+ !$omp atomic
+ b = b + 1
+ !$omp atomic
+ d(1) = d(1) + 1
+ r = r + 1
+ !$omp end parallel
+ if (b.ne.r+r2.or.d(1).ne.r+r2) call abort
+ end subroutine foo
+ subroutine bar (a, c)
+ integer, pointer :: a, c(:), b, d(:)
+ integer, target :: q, r(5)
+ integer :: i
+ q = 17
+ r = 21
+ b => a
+ d => c
+ !$omp parallel do firstprivate (a, c) lastprivate (a, c)
+ do i = 1, 100
+ !$omp atomic
+ a = a + 1
+ !$omp atomic
+ c((i+9)/10) = c((i+9)/10) + 1
+ if (i.eq.100) then
+ a => q
+ c => r
+ end if
+ end do
+ !$omp end parallel do
+ if (b.ne.100.or.any(d.ne.10)) call abort
+ if (a.ne.17.or.any(c.ne.21)) call abort
+ a => b
+ c => d
+ !$omp parallel do firstprivate (b, d) lastprivate (b, d)
+ do i = 1, 100
+ !$omp atomic
+ b = b + 1
+ !$omp atomic
+ d((i+9)/10) = d((i+9)/10) + 1
+ if (i.eq.100) then
+ b => q
+ d => r
+ end if
+ end do
+ !$omp end parallel do
+ if (a.ne.200.or.any(c.ne.20)) call abort
+ if (b.ne.17.or.any(d.ne.21)) call abort
+ end subroutine bar
+end
--- /dev/null
+! { dg-do run }
+! { dg-require-effective-target tls_runtime }
+ integer, pointer, save :: thr(:)
+!$omp threadprivate (thr)
+ integer, target :: s(3), t(3), u(3)
+ integer :: i
+ logical :: l
+ s = 2
+ t = 7
+ u = 13
+ thr => t
+ l = .false.
+ i = 0
+!$omp parallel copyin (thr) reduction(.or.:l) reduction(+:i)
+ if (any (thr.ne.7)) l = .true.
+ thr => s
+!$omp master
+ thr => u
+!$omp end master
+!$omp atomic
+ thr(1) = thr(1) + 1
+ i = i + 1
+!$omp end parallel
+ if (l) call abort
+ if (thr(1).ne.14) call abort
+ if (s(1).ne.1+i) call abort
+ if (u(1).ne.14) call abort
+end
--- /dev/null
+! { dg-do run }
+
+ use omp_lib
+ integer :: err, e
+
+!$omp atomic write
+ err = 0
+!$omp parallel shared(err) private(e)
+ if (omp_in_final ()) then
+!$omp atomic write
+ err = 1
+ endif
+!$omp task if (.false.) shared(err)
+ if (omp_in_final ()) then
+!$omp atomic write
+ err = 1
+ endif
+!$omp task if (.false.) shared(err)
+ if (omp_in_final ()) then
+!$omp atomic write
+ err = 1
+ endif
+!$omp end task
+!$omp end task
+!$omp atomic read
+ e = err
+!$omp task final (e .eq. 0) shared(err)
+ if (.not.omp_in_final ()) then
+!$omp atomic write
+ err = 1
+ endif
+!$omp taskyield
+!$omp taskwait
+!$omp task shared(err)
+ if (.not.omp_in_final ()) then
+!$omp atomic write
+ err = 1
+ endif
+!$omp end task
+!$omp end task
+!$omp end parallel
+!$omp atomic read
+ e = err
+ if (e .ne. 0) call abort
+end