diff options
author | Jakub Jelinek <jakub@redhat.com> | 2022-09-27 08:23:08 +0200 |
---|---|---|
committer | Jakub Jelinek <jakub@redhat.com> | 2022-09-27 08:23:08 +0200 |
commit | 4790fe99f236c7f1b617722403e682ba2f82485f (patch) | |
tree | 2b247f6e88dc3f479497f74215bf1be01f127232 /gcc/cp | |
parent | 5b86d5dbe47c477daf739b82c3793a70f8cbd96c (diff) | |
download | gcc-4790fe99f236c7f1b617722403e682ba2f82485f.zip gcc-4790fe99f236c7f1b617722403e682ba2f82485f.tar.gz gcc-4790fe99f236c7f1b617722403e682ba2f82485f.tar.bz2 |
openmp: Add OpenMP assume, assumes and begin/end assumes support
The following patch implements OpenMP 5.1
#pragma omp assume
#pragma omp assumes
and
#pragma omp begin assumes
#pragma omp end assumes
directive support for C and C++. Currently it doesn't remember
anything from the assumption clauses for later, so is mainly
to support the directives and diagnose errors in their use.
If the recently posted C++23 [[assume (cond)]]; support makes it
in, the intent is that this can be easily adjusted at least for
the #pragma omp assume directive with holds clause(s) to use
the same infrastructure. Now, C++23 portable assumptions are slightly
different from OpenMP 5.1 assumptions' holds clause in that C++23
assumption holds just where it appears, while OpenMP 5.1 assumptions
hold everywhere in the scope of the directive. For assumes
directive which can appear at file or namespace scope it is the whole
TU and everything that functions from there call at runtime, for
begin assumes/end assumes pair all the functions in between those
directives and everything they call and for assume directive the
associated (currently structured) block. I have no idea how to
represents such holds to be usable for optimizers, except to
make
#pragma omp assume holds (cond)
block;
expand essentially to
[[assume (cond)]];
block;
or
[[assume (cond)]];
block;
[[assume (cond)]];
for now. Except for holds clause, the other assumptions are
OpenMP related, I'd say we should brainstorm where it would be
useful to optimize based on such information (I guess e.g. in target
regions it easily could) and only when we come up with something
like that think about how to propagate the assumptions to the optimizers.
2022-09-27 Jakub Jelinek <jakub@redhat.com>
gcc/c-family/
* c-pragma.h (enum pragma_kind): Add PRAGMA_OMP_ASSUME,
PRAGMA_OMP_ASSUMES and PRAGMA_OMP_BEGIN. Rename
PRAGMA_OMP_END_DECLARE_TARGET to PRAGMA_OMP_END.
* c-pragma.cc (omp_pragmas): Add assumes and begin.
For end rename PRAGMA_OMP_END_DECLARE_TARGET to PRAGMA_OMP_END.
(omp_pragmas_simd): Add assume.
* c-common.h (c_omp_directives): Declare.
* c-omp.cc (omp_directives): Rename to ...
(c_omp_directives): ... this. No longer static. Uncomment
assume, assumes, begin assumes and end assumes entries.
In end declare target entry rename PRAGMA_OMP_END_DECLARE_TARGET
to PRAGMA_OMP_END.
(c_omp_categorize_directive): Adjust for omp_directives to
c_omp_directives renaming.
gcc/c/
* c-lang.h (current_omp_begin_assumes): Declare.
* c-parser.cc: Include bitmap.h.
(c_parser_omp_end_declare_target): Rename to ...
(c_parser_omp_end): ... this. Handle also end assumes.
(c_parser_omp_begin, c_parser_omp_assumption_clauses,
c_parser_omp_assumes, c_parser_omp_assume): New functions.
(c_parser_translation_unit): Also diagnose #pragma omp begin assumes
without corresponding #pragma omp end assumes.
(c_parser_pragma): Use %s in may only be used at file scope
diagnostics to decrease number of translatable messages. Handle
PRAGMA_OMP_BEGIN and PRAGMA_OMP_ASSUMES. Handle PRAGMA_OMP_END
rather than PRAGMA_OMP_END_DECLARE_TARGET and call c_parser_omp_end
for it rather than c_parser_omp_end_declare_target.
(c_parser_omp_construct): Handle PRAGMA_OMP_ASSUME.
* c-decl.cc (current_omp_begin_assumes): Define.
gcc/cp/
* cp-tree.h (struct omp_begin_assumes_data): New type.
(struct saved_scope): Add omp_begin_assumes member.
* parser.cc: Include bitmap.h.
(cp_parser_omp_assumption_clauses, cp_parser_omp_assume,
cp_parser_omp_assumes, cp_parser_omp_begin): New functions.
(cp_parser_omp_end_declare_target): Rename to ...
(cp_parser_omp_end): ... this. Handle also end assumes.
(cp_parser_omp_construct): Handle PRAGMA_OMP_ASSUME.
(cp_parser_pragma): Handle PRAGMA_OMP_ASSUME, PRAGMA_OMP_ASSUMES
and PRAGMA_OMP_BEGIN. Handle PRAGMA_OMP_END rather than
PRAGMA_OMP_END_DECLARE_TARGET and call cp_parser_omp_end
for it rather than cp_parser_omp_end_declare_target.
* pt.cc (apply_late_template_attributes): Also temporarily clear
omp_begin_assumes.
* semantics.cc (finish_translation_unit): Also diagnose
#pragma omp begin assumes without corresponding
#pragma omp end assumes.
gcc/testsuite/
* c-c++-common/gomp/assume-1.c: New test.
* c-c++-common/gomp/assume-2.c: New test.
* c-c++-common/gomp/assume-3.c: New test.
* c-c++-common/gomp/assumes-1.c: New test.
* c-c++-common/gomp/assumes-2.c: New test.
* c-c++-common/gomp/assumes-3.c: New test.
* c-c++-common/gomp/assumes-4.c: New test.
* c-c++-common/gomp/begin-assumes-1.c: New test.
* c-c++-common/gomp/begin-assumes-2.c: New test.
* c-c++-common/gomp/begin-assumes-3.c: New test.
* c-c++-common/gomp/begin-assumes-4.c: New test.
* c-c++-common/gomp/declare-target-6.c: New test.
* g++.dg/gomp/attrs-1.C (bar): Add n1 and n2 arguments, add
tests for assume directive.
* g++.dg/gomp/attrs-2.C (bar): Likewise.
* g++.dg/gomp/attrs-9.C: Add n1 and n2 variables, add tests for
begin assumes directive.
* g++.dg/gomp/attrs-15.C: New test.
* g++.dg/gomp/attrs-16.C: New test.
* g++.dg/gomp/attrs-17.C: New test.
Diffstat (limited to 'gcc/cp')
-rw-r--r-- | gcc/cp/cp-tree.h | 5 | ||||
-rw-r--r-- | gcc/cp/parser.cc | 340 | ||||
-rw-r--r-- | gcc/cp/pt.cc | 1 | ||||
-rw-r--r-- | gcc/cp/semantics.cc | 7 |
4 files changed, 328 insertions, 25 deletions
diff --git a/gcc/cp/cp-tree.h b/gcc/cp/cp-tree.h index 8779538..51fd0cf 100644 --- a/gcc/cp/cp-tree.h +++ b/gcc/cp/cp-tree.h @@ -1834,6 +1834,10 @@ struct GTY(()) omp_declare_target_attr { bool attr_syntax; }; +struct GTY(()) omp_begin_assumes_data { + bool attr_syntax; +}; + /* Global state. */ struct GTY(()) saved_scope { @@ -1881,6 +1885,7 @@ struct GTY(()) saved_scope { hash_map<tree, tree> *GTY((skip)) x_local_specializations; vec<omp_declare_target_attr, va_gc> *omp_declare_target_attribute; + vec<omp_begin_assumes_data, va_gc> *omp_begin_assumes; struct saved_scope *prev; }; diff --git a/gcc/cp/parser.cc b/gcc/cp/parser.cc index d876a86..4bd3ca1 100644 --- a/gcc/cp/parser.cc +++ b/gcc/cp/parser.cc @@ -46,6 +46,7 @@ along with GCC; see the file COPYING3. If not see #include "cp-name-hint.h" #include "memmodel.h" #include "c-family/known-headers.h" +#include "bitmap.h" /* The lexer. */ @@ -46061,6 +46062,218 @@ cp_parser_omp_context_selector_specification (cp_parser *parser, return nreverse (ret); } +/* Assumption clauses: + OpenMP 5.1 + absent (directive-name-list) + contains (directive-name-list) + holds (expression) + no_openmp + no_openmp_routines + no_parallelism */ + +static void +cp_parser_omp_assumption_clauses (cp_parser *parser, cp_token *pragma_tok, + bool is_assume) +{ + bool first = true; + bool no_openmp = false; + bool no_openmp_routines = false; + bool no_parallelism = false; + bitmap_head absent_head, contains_head; + + bitmap_obstack_initialize (NULL); + bitmap_initialize (&absent_head, &bitmap_default_obstack); + bitmap_initialize (&contains_head, &bitmap_default_obstack); + + if (cp_lexer_next_token_is (parser->lexer, CPP_PRAGMA_EOL)) + error_at (cp_lexer_peek_token (parser->lexer)->location, + "expected at least one assumption clause"); + + while (cp_lexer_next_token_is_not (parser->lexer, CPP_PRAGMA_EOL)) + { + /* For now only in C++ attributes, do it always for OpenMP 5.1. */ + if ((!first || parser->lexer->in_omp_attribute_pragma) + && cp_lexer_next_token_is (parser->lexer, CPP_COMMA) + && cp_lexer_nth_token_is (parser->lexer, 2, CPP_NAME)) + cp_lexer_consume_token (parser->lexer); + + first = false; + + if (!cp_lexer_next_token_is (parser->lexer, CPP_NAME)) + break; + + const char *p + = IDENTIFIER_POINTER (cp_lexer_peek_token (parser->lexer)->u.value); + location_t cloc = cp_lexer_peek_token (parser->lexer)->location; + + if (!strcmp (p, "no_openmp")) + { + cp_lexer_consume_token (parser->lexer); + if (no_openmp) + error_at (cloc, "too many %qs clauses", "no_openmp"); + no_openmp = true; + } + else if (!strcmp (p, "no_openmp_routines")) + { + cp_lexer_consume_token (parser->lexer); + if (no_openmp_routines) + error_at (cloc, "too many %qs clauses", "no_openmp_routines"); + no_openmp_routines = true; + } + else if (!strcmp (p, "no_parallelism")) + { + cp_lexer_consume_token (parser->lexer); + if (no_parallelism) + error_at (cloc, "too many %qs clauses", "no_parallelism"); + no_parallelism = true; + } + else if (!strcmp (p, "holds")) + { + cp_lexer_consume_token (parser->lexer); + matching_parens parens; + if (parens.require_open (parser)) + { + tree t = cp_parser_assignment_expression (parser); + if (!type_dependent_expression_p (t)) + t = contextual_conv_bool (t, tf_warning_or_error); + if (is_assume) + { + /* FIXME: Emit .ASSUME (t) call here. */ + (void) t; + } + if (!parens.require_close (parser)) + cp_parser_skip_to_closing_parenthesis (parser, + /*recovering=*/true, + /*or_comma=*/false, + /*consume_paren=*/true); + } + } + else if (!strcmp (p, "absent") || !strcmp (p, "contains")) + { + cp_lexer_consume_token (parser->lexer); + matching_parens parens; + if (parens.require_open (parser)) + { + do + { + const char *directive[3] = {}; + int i; + location_t dloc + = cp_lexer_peek_token (parser->lexer)->location; + for (i = 0; i < 3; i++) + { + tree id; + if (cp_lexer_nth_token_is (parser->lexer, i + 1, CPP_NAME)) + id = cp_lexer_peek_nth_token (parser->lexer, + i + 1)->u.value; + else if (cp_lexer_nth_token_is (parser->lexer, i + 1, + CPP_KEYWORD)) + { + enum rid rid + = cp_lexer_peek_nth_token (parser->lexer, + i + 1)->keyword; + id = ridpointers[rid]; + } + else + break; + directive[i] = IDENTIFIER_POINTER (id); + } + if (i == 0) + error_at (dloc, "expected directive name"); + else + { + const struct c_omp_directive *dir + = c_omp_categorize_directive (directive[0], + directive[1], + directive[2]); + if (dir == NULL + || dir->kind == C_OMP_DIR_DECLARATIVE + || dir->kind == C_OMP_DIR_INFORMATIONAL + || dir->id == PRAGMA_OMP_END + || (!dir->second && directive[1]) + || (!dir->third && directive[2])) + error_at (dloc, "unknown OpenMP directive name in " + "%qs clause argument", p); + else + { + int id = dir - c_omp_directives; + if (bitmap_bit_p (p[0] == 'a' ? &contains_head + : &absent_head, id)) + error_at (dloc, "%<%s%s%s%s%s%> directive " + "mentioned in both %<absent%> and " + "%<contains%> clauses", + directive[0], + directive[1] ? " " : "", + directive[1] ? directive[1] : "", + directive[2] ? " " : "", + directive[2] ? directive[2] : ""); + else if (!bitmap_set_bit (p[0] == 'a' + ? &absent_head + : &contains_head, id)) + error_at (dloc, "%<%s%s%s%s%s%> directive " + "mentioned multiple times in %qs " + "clauses", + directive[0], + directive[1] ? " " : "", + directive[1] ? directive[1] : "", + directive[2] ? " " : "", + directive[2] ? directive[2] : "", p); + } + for (; i; --i) + cp_lexer_consume_token (parser->lexer); + } + if (cp_lexer_next_token_is (parser->lexer, CPP_COMMA)) + cp_lexer_consume_token (parser->lexer); + else + break; + } + while (1); + if (!parens.require_close (parser)) + cp_parser_skip_to_closing_parenthesis (parser, + /*recovering=*/true, + /*or_comma=*/false, + /*consume_paren=*/true); + } + } + else if (startswith (p, "ext_")) + { + warning_at (cloc, 0, "unknown assumption clause %qs", p); + cp_lexer_consume_token (parser->lexer); + if (cp_lexer_next_token_is (parser->lexer, CPP_OPEN_PAREN)) + for (size_t n = cp_parser_skip_balanced_tokens (parser, 1) - 1; + n; --n) + cp_lexer_consume_token (parser->lexer); + } + else + { + cp_lexer_consume_token (parser->lexer); + error_at (cloc, "expected assumption clause"); + break; + } + } + cp_parser_skip_to_pragma_eol (parser, pragma_tok); +} + +/* OpenMP 5.1 + # pragma omp assume clauses[optseq] new-line */ + +static void +cp_parser_omp_assume (cp_parser *parser, cp_token *pragma_tok, bool *if_p) +{ + cp_parser_omp_assumption_clauses (parser, pragma_tok, true); + add_stmt (cp_parser_omp_structured_block (parser, if_p)); +} + +/* OpenMP 5.1 + # pragma omp assumes clauses[optseq] new-line */ + +static bool +cp_parser_omp_assumes (cp_parser *parser, cp_token *pragma_tok) +{ + cp_parser_omp_assumption_clauses (parser, pragma_tok, false); + return false; +} + /* Finalize #pragma omp declare variant after a fndecl has been parsed, and put that into "omp declare variant base" attribute. */ @@ -46510,8 +46723,41 @@ cp_parser_omp_declare_target (cp_parser *parser, cp_token *pragma_tok) "directive with only %<device_type%> clauses ignored"); } +/* OpenMP 5.1 + #pragma omp begin assumes clauses[optseq] new-line */ + +static void +cp_parser_omp_begin (cp_parser *parser, cp_token *pragma_tok) +{ + const char *p = ""; + bool in_omp_attribute_pragma = parser->lexer->in_omp_attribute_pragma; + if (cp_lexer_next_token_is (parser->lexer, CPP_NAME)) + { + tree id = cp_lexer_peek_token (parser->lexer)->u.value; + p = IDENTIFIER_POINTER (id); + } + if (strcmp (p, "assumes") == 0) + { + cp_lexer_consume_token (parser->lexer); + cp_parser_omp_assumption_clauses (parser, pragma_tok, false); + struct omp_begin_assumes_data a = { in_omp_attribute_pragma }; + vec_safe_push (scope_chain->omp_begin_assumes, a); + } + else + { + cp_parser_error (parser, "expected %<assumes%>"); + cp_parser_skip_to_pragma_eol (parser, pragma_tok); + } +} + +/* OpenMP 4.0: + # pragma omp end declare target new-line + + OpenMP 5.1: + # pragma omp end assumes new-line */ + static void -cp_parser_omp_end_declare_target (cp_parser *parser, cp_token *pragma_tok) +cp_parser_omp_end (cp_parser *parser, cp_token *pragma_tok) { const char *p = ""; bool in_omp_attribute_pragma = parser->lexer->in_omp_attribute_pragma; @@ -46537,33 +46783,58 @@ cp_parser_omp_end_declare_target (cp_parser *parser, cp_token *pragma_tok) cp_parser_skip_to_pragma_eol (parser, pragma_tok); return; } + cp_parser_require_pragma_eol (parser, pragma_tok); + if (!vec_safe_length (scope_chain->omp_declare_target_attribute)) + error_at (pragma_tok->location, + "%<#pragma omp end declare target%> without corresponding " + "%<#pragma omp declare target%>"); + else + { + omp_declare_target_attr + a = scope_chain->omp_declare_target_attribute->pop (); + if (a.attr_syntax != in_omp_attribute_pragma) + { + if (a.attr_syntax) + error_at (pragma_tok->location, + "%<declare target%> in attribute syntax terminated " + "with %<end declare target%> in pragma syntax"); + else + error_at (pragma_tok->location, + "%<declare target%> in pragma syntax terminated " + "with %<end declare target%> in attribute syntax"); + } + } } - else + else if (strcmp (p, "assumes") == 0) { - cp_parser_error (parser, "expected %<declare%>"); - cp_parser_skip_to_pragma_eol (parser, pragma_tok); - return; + cp_lexer_consume_token (parser->lexer); + cp_parser_require_pragma_eol (parser, pragma_tok); + if (!vec_safe_length (scope_chain->omp_begin_assumes)) + error_at (pragma_tok->location, + "%<#pragma omp end assumes%> without corresponding " + "%<#pragma omp begin assumes%>"); + else + { + omp_begin_assumes_data + a = scope_chain->omp_begin_assumes->pop (); + if (a.attr_syntax != in_omp_attribute_pragma) + { + if (a.attr_syntax) + error_at (pragma_tok->location, + "%<begin assumes%> in attribute syntax terminated " + "with %<end assumes%> in pragma syntax"); + else + error_at (pragma_tok->location, + "%<begin assumes%> in pragma syntax terminated " + "with %<end assumes%> in attribute syntax"); + } + } } - cp_parser_require_pragma_eol (parser, pragma_tok); - if (!vec_safe_length (scope_chain->omp_declare_target_attribute)) - error_at (pragma_tok->location, - "%<#pragma omp end declare target%> without corresponding " - "%<#pragma omp declare target%>"); else { - omp_declare_target_attr - a = scope_chain->omp_declare_target_attribute->pop (); - if (a.attr_syntax != in_omp_attribute_pragma) - { - if (a.attr_syntax) - error_at (pragma_tok->location, - "%<declare target%> in attribute syntax terminated " - "with %<end declare target%> in pragma syntax"); - else - error_at (pragma_tok->location, - "%<declare target%> in pragma syntax terminated " - "with %<end declare target%> in attribute syntax"); - } + cp_parser_error (parser, "expected %<declare%> or %<assumes%>"); + cp_parser_skip_to_pragma_eol (parser, pragma_tok); + return; } } @@ -47846,6 +48117,9 @@ cp_parser_omp_construct (cp_parser *parser, cp_token *pragma_tok, bool *if_p) stmt = cp_parser_omp_teams (parser, pragma_tok, p_name, mask, NULL, if_p); break; + case PRAGMA_OMP_ASSUME: + cp_parser_omp_assume (parser, pragma_tok, if_p); + return; default: gcc_unreachable (); } @@ -48449,6 +48723,7 @@ cp_parser_pragma (cp_parser *parser, enum pragma_context context, bool *if_p) case PRAGMA_OACC_LOOP: case PRAGMA_OACC_PARALLEL: case PRAGMA_OACC_SERIAL: + case PRAGMA_OMP_ASSUME: case PRAGMA_OMP_ATOMIC: case PRAGMA_OMP_CRITICAL: case PRAGMA_OMP_DISTRIBUTE: @@ -48483,6 +48758,17 @@ cp_parser_pragma (cp_parser *parser, enum pragma_context context, bool *if_p) } return cp_parser_omp_requires (parser, pragma_tok); + case PRAGMA_OMP_ASSUMES: + if (context != pragma_external) + { + error_at (pragma_tok->location, + "%<#pragma omp assumes%> may only be used at file or " + "namespace scope"); + ret = true; + break; + } + return cp_parser_omp_assumes (parser, pragma_tok); + case PRAGMA_OMP_NOTHING: cp_parser_omp_nothing (parser, pragma_tok); return false; @@ -48506,8 +48792,12 @@ cp_parser_pragma (cp_parser *parser, enum pragma_context context, bool *if_p) pop_omp_privatization_clauses (stmt); return ret; - case PRAGMA_OMP_END_DECLARE_TARGET: - cp_parser_omp_end_declare_target (parser, pragma_tok); + case PRAGMA_OMP_BEGIN: + cp_parser_omp_begin (parser, pragma_tok); + return false; + + case PRAGMA_OMP_END: + cp_parser_omp_end (parser, pragma_tok); return false; case PRAGMA_OMP_SCAN: diff --git a/gcc/cp/pt.cc b/gcc/cp/pt.cc index 1f088fe..1c1e573 100644 --- a/gcc/cp/pt.cc +++ b/gcc/cp/pt.cc @@ -11945,6 +11945,7 @@ apply_late_template_attributes (tree *decl_p, tree attributes, int attr_flags, auto o3 = make_temp_override (current_target_pragma, NULL_TREE); auto o4 = make_temp_override (scope_chain->omp_declare_target_attribute, NULL); + auto o5 = make_temp_override (scope_chain->omp_begin_assumes, NULL); cplus_decl_attributes (decl_p, late_attrs, attr_flags); diff --git a/gcc/cp/semantics.cc b/gcc/cp/semantics.cc index 92fc795..e8cd505 100644 --- a/gcc/cp/semantics.cc +++ b/gcc/cp/semantics.cc @@ -3363,6 +3363,13 @@ finish_translation_unit (void) "%<#pragma omp end declare target%>"); vec_safe_truncate (scope_chain->omp_declare_target_attribute, 0); } + if (vec_safe_length (scope_chain->omp_begin_assumes)) + { + if (!errorcount) + error ("%<#pragma omp begin assumes%> without corresponding " + "%<#pragma omp end assumes%>"); + vec_safe_truncate (scope_chain->omp_begin_assumes, 0); + } } /* Finish a template type parameter, specified as AGGR IDENTIFIER. |