This is the mail archive of the
gcc-patches@gcc.gnu.org
mailing list for the GCC project.
[gomp5] OpenMP flush with memory-order-clause
- From: Jakub Jelinek <jakub at redhat dot com>
- To: gcc-patches at gcc dot gnu dot org
- Date: Tue, 19 Jun 2018 11:18:26 +0200
- Subject: [gomp5] OpenMP flush with memory-order-clause
- Reply-to: Jakub Jelinek <jakub at redhat dot com>
Hi!
The flush directive can now have optional memory-order clause.
Tested on x86_64-linux, committed to gomp-5_0-branch.
2018-06-19 Jakub Jelinek <jakub@redhat.com>
c-family/
* c-common.h (c_finish_omp_flush): Add MO argument.
* c-omp.c: Include memmodel.h.
(c_finish_omp_flush): Add MO argument, if not MEMMODEL_LAST, emit
__atomic_thread_fence call with the given value.
c/
* c-parser.c: Include memmodel.h.
(c_parser_omp_flush): Parse flush with memory-order-clause.
cp/
* cp-tree.h (finish_omp_flush): Add MO argument.
* parser.c: Include memmodel.h.
(cp_parser_omp_flush): Parse flush with memory-order-clause.
* semantics.c (finish_omp_flush): Add MO argument, if not
MEMMODEL_LAST, emit __atomic_thread_fence call with the given value.
testsuite/
* c-c++-common/gomp/flush-1.c: New test.
* c-c++-common/gomp/flush-2.c: New test.
--- gcc/c-family/c-common.h.jj 2018-06-04 18:16:27.363395319 +0200
+++ gcc/c-family/c-common.h 2018-06-19 10:42:21.289381950 +0200
@@ -1149,7 +1149,7 @@ extern void c_finish_omp_barrier (locati
extern tree c_finish_omp_atomic (location_t, enum tree_code, enum tree_code,
tree, tree, tree, tree, tree, bool,
enum omp_memory_order, bool = false);
-extern void c_finish_omp_flush (location_t);
+extern void c_finish_omp_flush (location_t, int);
extern void c_finish_omp_taskwait (location_t);
extern void c_finish_omp_taskyield (location_t);
extern tree c_finish_omp_for (location_t, enum tree_code, tree, tree, tree,
--- gcc/c-family/c-omp.c.jj 2018-06-04 19:21:03.361751435 +0200
+++ gcc/c-family/c-omp.c 2018-06-19 10:42:21.290381951 +0200
@@ -30,6 +30,7 @@ along with GCC; see the file COPYING3.
#include "c-pragma.h"
#include "omp-general.h"
#include "gomp-constants.h"
+#include "memmodel.h"
/* Complete a #pragma oacc wait construct. LOC is the location of
@@ -421,12 +422,21 @@ c_finish_omp_atomic (location_t loc, enu
the #pragma. */
void
-c_finish_omp_flush (location_t loc)
+c_finish_omp_flush (location_t loc, int mo)
{
tree x;
- x = builtin_decl_explicit (BUILT_IN_SYNC_SYNCHRONIZE);
- x = build_call_expr_loc (loc, x, 0);
+ if (mo == MEMMODEL_LAST)
+ {
+ x = builtin_decl_explicit (BUILT_IN_SYNC_SYNCHRONIZE);
+ x = build_call_expr_loc (loc, x, 0);
+ }
+ else
+ {
+ x = builtin_decl_explicit (BUILT_IN_ATOMIC_THREAD_FENCE);
+ x = build_call_expr_loc (loc, x, 1,
+ build_int_cst (integer_type_node, mo));
+ }
add_stmt (x);
}
--- gcc/c/c-parser.c.jj 2018-06-18 19:07:09.152186493 +0200
+++ gcc/c/c-parser.c 2018-06-19 10:42:21.288381950 +0200
@@ -68,6 +68,7 @@ along with GCC; see the file COPYING3.
#include "intl.h"
#include "c-family/name-hint.h"
#include "tree-iterator.h"
+#include "memmodel.h"
/* We need to walk over decls with incomplete struct/union/enum types
after parsing the whole translation unit.
@@ -16109,20 +16110,46 @@ c_parser_omp_critical (location_t loc, c
# pragma omp flush flush-vars[opt] new-line
flush-vars:
- ( variable-list ) */
+ ( variable-list )
+
+ OpenMP 5.0:
+ # pragma omp flush memory-order-clause new-line */
static void
c_parser_omp_flush (c_parser *parser)
{
location_t loc = c_parser_peek_token (parser)->location;
c_parser_consume_pragma (parser);
+ enum memmodel mo = MEMMODEL_LAST;
+ if (c_parser_next_token_is (parser, CPP_NAME))
+ {
+ const char *p
+ = IDENTIFIER_POINTER (c_parser_peek_token (parser)->value);
+
+ if (!strcmp (p, "acq_rel"))
+ mo = MEMMODEL_ACQ_REL;
+ else if (!strcmp (p, "release"))
+ mo = MEMMODEL_RELEASE;
+ else if (!strcmp (p, "acquire"))
+ mo = MEMMODEL_ACQUIRE;
+ else
+ error_at (c_parser_peek_token (parser)->location,
+ "expected %<acq_rel%>, %<release%> or %<acquire%>");
+ c_parser_consume_token (parser);
+ }
if (c_parser_next_token_is (parser, CPP_OPEN_PAREN))
- c_parser_omp_var_list_parens (parser, OMP_CLAUSE_ERROR, NULL);
+ {
+ if (mo != MEMMODEL_LAST)
+ error_at (c_parser_peek_token (parser)->location,
+ "%<flush%> list specified together with memory order "
+ "clause");
+ c_parser_omp_var_list_parens (parser, OMP_CLAUSE_ERROR, NULL);
+ }
else if (c_parser_next_token_is_not (parser, CPP_PRAGMA_EOL))
c_parser_error (parser, "expected %<(%> or end of line");
c_parser_skip_to_pragma_eol (parser);
- c_finish_omp_flush (loc);
+ c_finish_omp_flush (loc, mo);
}
/* Parse the restricted form of loop statements allowed by OpenACC and OpenMP.
--- gcc/cp/cp-tree.h.jj 2018-06-04 18:17:56.411535752 +0200
+++ gcc/cp/cp-tree.h 2018-06-19 10:42:21.292381953 +0200
@@ -6968,7 +6968,7 @@ extern void finish_omp_atomic (enum tr
tree, tree, tree, tree, tree,
tree, enum omp_memory_order);
extern void finish_omp_barrier (void);
-extern void finish_omp_flush (void);
+extern void finish_omp_flush (int);
extern void finish_omp_taskwait (void);
extern void finish_omp_taskyield (void);
extern void finish_omp_cancel (tree);
--- gcc/cp/parser.c.jj 2018-06-18 19:07:09.152186493 +0200
+++ gcc/cp/parser.c 2018-06-19 10:42:21.296381957 +0200
@@ -44,6 +44,7 @@ along with GCC; see the file COPYING3.
#include "gcc-rich-location.h"
#include "tree-iterator.h"
#include "c-family/name-hint.h"
+#include "memmodel.h"
/* The lexer. */
@@ -35256,16 +35257,41 @@ cp_parser_omp_critical (cp_parser *parse
# pragma omp flush flush-vars[opt] new-line
flush-vars:
- ( variable-list ) */
+ ( variable-list )
+
+ OpenMP 5.0:
+ # pragma omp flush memory-order-clause new-line */
static void
cp_parser_omp_flush (cp_parser *parser, cp_token *pragma_tok)
{
+ enum memmodel mo = MEMMODEL_LAST;
+ 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, "acq_rel"))
+ mo = MEMMODEL_ACQ_REL;
+ else if (!strcmp (p, "release"))
+ mo = MEMMODEL_RELEASE;
+ else if (!strcmp (p, "acquire"))
+ mo = MEMMODEL_ACQUIRE;
+ else
+ error_at (cp_lexer_peek_token (parser->lexer)->location,
+ "expected %<acq_rel%>, %<release%> or %<acquire%>");
+ cp_lexer_consume_token (parser->lexer);
+ }
if (cp_lexer_next_token_is (parser->lexer, CPP_OPEN_PAREN))
- (void) cp_parser_omp_var_list (parser, OMP_CLAUSE_ERROR, NULL);
+ {
+ if (mo != MEMMODEL_LAST)
+ error_at (cp_lexer_peek_token (parser->lexer)->location,
+ "%<flush%> list specified together with memory order "
+ "clause");
+ (void) cp_parser_omp_var_list (parser, OMP_CLAUSE_ERROR, NULL);
+ }
cp_parser_require_pragma_eol (parser, pragma_tok);
- finish_omp_flush ();
+ finish_omp_flush (mo);
}
/* Helper function, to parse omp for increment expression. */
--- gcc/cp/semantics.c.jj 2018-06-13 19:25:03.003926735 +0200
+++ gcc/cp/semantics.c 2018-06-19 10:42:21.297381958 +0200
@@ -44,6 +44,7 @@ along with GCC; see the file COPYING3.
#include "attribs.h"
#include "gomp-constants.h"
#include "predict.h"
+#include "memmodel.h"
/* There routines provide a modular interface to perform many parsing
operations. They may therefore be used during actual parsing, or
@@ -8754,10 +8755,15 @@ finish_omp_barrier (void)
}
void
-finish_omp_flush (void)
+finish_omp_flush (int mo)
{
tree fn = builtin_decl_explicit (BUILT_IN_SYNC_SYNCHRONIZE);
vec<tree, va_gc> *vec = make_tree_vector ();
+ if (mo != MEMMODEL_LAST)
+ {
+ fn = builtin_decl_explicit (BUILT_IN_ATOMIC_THREAD_FENCE);
+ vec->quick_push (build_int_cst (integer_type_node, mo));
+ }
tree stmt = finish_call_expr (fn, &vec, false, false, tf_warning_or_error);
release_tree_vector (vec);
finish_expr_stmt (stmt);
--- gcc/testsuite/c-c++-common/gomp/flush-1.c.jj 2018-06-19 10:56:51.074211728 +0200
+++ gcc/testsuite/c-c++-common/gomp/flush-1.c 2018-06-19 10:56:44.314202801 +0200
@@ -0,0 +1,39 @@
+/* { dg-additional-options "-fdump-tree-gimple" } */
+/* { dg-final { scan-tree-dump "foo \\(4\\);\[\n\r]* __atomic_thread_fence \\(4\\);\[\n\r]* foo \\(4\\);" "gimple" } } */
+/* { dg-final { scan-tree-dump "foo \\(3\\);\[\n\r]* __atomic_thread_fence \\(3\\);\[\n\r]* foo \\(3\\);" "gimple" } } */
+/* { dg-final { scan-tree-dump "foo \\(2\\);\[\n\r]* __atomic_thread_fence \\(2\\);\[\n\r]* foo \\(2\\);" "gimple" } } */
+/* { dg-final { scan-tree-dump "foo \\(5\\);\[\n\r]* __sync_synchronize \\(\\);\[\n\r]* foo \\(5\\);" "gimple" } } */
+
+void foo (int);
+
+void
+f1 (void)
+{
+ foo (4);
+ #pragma omp flush acq_rel
+ foo (4);
+}
+
+void
+f2 (void)
+{
+ foo (3);
+ #pragma omp flush release
+ foo (3);
+}
+
+void
+f3 (void)
+{
+ foo (2);
+ #pragma omp flush acquire
+ foo (2);
+}
+
+void
+f4 (void)
+{
+ foo (5);
+ #pragma omp flush
+ foo (5);
+}
--- gcc/testsuite/c-c++-common/gomp/flush-2.c.jj 2018-06-19 10:58:33.981347616 +0200
+++ gcc/testsuite/c-c++-common/gomp/flush-2.c 2018-06-19 10:59:27.909418839 +0200
@@ -0,0 +1,17 @@
+int a, b;
+
+void
+foo (void)
+{
+ #pragma omp flush
+ #pragma omp flush (a, b)
+ #pragma omp flush acquire
+ #pragma omp flush release
+ #pragma omp flush acq_rel
+ #pragma omp flush relaxed /* { dg-error "expected 'acq_rel', 'release' or 'acquire'" } */
+ #pragma omp flush seq_cst /* { dg-error "expected 'acq_rel', 'release' or 'acquire'" } */
+ #pragma omp flush foobar /* { dg-error "expected 'acq_rel', 'release' or 'acquire'" } */
+ #pragma omp flush acquire (a, b) /* { dg-error "'flush' list specified together with memory order clause" } */
+ #pragma omp flush release (a, b) /* { dg-error "'flush' list specified together with memory order clause" } */
+ #pragma omp flush acq_rel (a, b) /* { dg-error "'flush' list specified together with memory order clause" } */
+}
Jakub