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 <ja...@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