https://github.com/jtb20 created https://github.com/llvm/llvm-project/pull/92731
This is a minimal patch to support parsing for "omp assume" directives. These are meant to be hints to a compiler' optimisers: as such, it is legitimate (if not very useful) to ignore them. The patch builds on top of the existing support for "omp assumes" directives (note spelling!). Unlike the "omp [begin/end] assumes" directives, "omp assume" is associated with a compound statement, i.e. it can appear within a function. The "holds" assumption could (theoretically) be mapped onto the existing builtin "__builtin_assume", though the latter applies to a single point in the program, and the former to a range (i.e. the whole of the associated compound statement). This patch fixes sollve's OpenMP 5.1 "omp assume"-based tests. >From 1d2bd6b8083a1220fc6f59cc7c139f0a5e0f84c3 Mon Sep 17 00:00:00 2001 From: Julian Brown <julian.br...@amd.com> Date: Wed, 1 May 2024 06:35:59 -0500 Subject: [PATCH] [OpenMP] OpenMP 5.1 "assume" directive parsing support This is a minimal patch to support parsing for "omp assume" directives. These are meant to be hints to a compiler' optimisers: as such, it is legitimate (if not very useful) to ignore them. The patch builds on top of the existing support for "omp assumes" directives (note spelling!). Unlike the "omp [begin/end] assumes" directives, "omp assume" is associated with a compound statement, i.e. it can appear within a function. The "holds" assumption could (theoretically) be mapped onto the existing builtin "__builtin_assume", though the latter applies to a single point in the program, and the former to a range (i.e. the whole of the associated compound statement). This patch fixes sollve's OpenMP 5.1 "omp assume"-based tests. Change-Id: Ibd4a0e2af82c4ac818eaa3de8867a006307361ec --- clang/lib/Parse/ParseOpenMP.cpp | 22 +++++++++++++ clang/lib/Sema/SemaOpenMP.cpp | 3 +- clang/test/OpenMP/assume_lambda.cpp | 31 +++++++++++++++++ clang/test/OpenMP/assume_messages.c | 23 +++++++++++++ clang/test/OpenMP/assume_messages_attr.c | 23 +++++++++++++ clang/test/OpenMP/assume_template.cpp | 42 ++++++++++++++++++++++++ llvm/include/llvm/Frontend/OpenMP/OMP.td | 3 ++ 7 files changed, 146 insertions(+), 1 deletion(-) create mode 100644 clang/test/OpenMP/assume_lambda.cpp create mode 100644 clang/test/OpenMP/assume_messages.c create mode 100644 clang/test/OpenMP/assume_messages_attr.c create mode 100644 clang/test/OpenMP/assume_template.cpp diff --git a/clang/lib/Parse/ParseOpenMP.cpp b/clang/lib/Parse/ParseOpenMP.cpp index e959dd6378f46..5c1bb58227fde 100644 --- a/clang/lib/Parse/ParseOpenMP.cpp +++ b/clang/lib/Parse/ParseOpenMP.cpp @@ -2450,6 +2450,7 @@ Parser::DeclGroupPtrTy Parser::ParseOpenMPDeclarativeDirectiveWithExtDecl( case OMPD_target_teams_loop: case OMPD_parallel_loop: case OMPD_target_parallel_loop: + case OMPD_assume: Diag(Tok, diag::err_omp_unexpected_directive) << 1 << getOpenMPDirectiveName(DKind); break; @@ -3035,6 +3036,27 @@ StmtResult Parser::ParseOpenMPDeclarativeOrExecutableDirective( << 1 << getOpenMPDirectiveName(DKind); SkipUntil(tok::annot_pragma_openmp_end); break; + case OMPD_assume: { + ParseScope OMPDirectiveScope(this, Scope::FnScope | Scope::DeclScope | + Scope::CompoundStmtScope); + ParseOpenMPAssumesDirective(DKind, ConsumeToken()); + + SkipUntil(tok::annot_pragma_openmp_end); + + ParsingOpenMPDirectiveRAII NormalScope(*this); + StmtResult AssociatedStmt; + { + Sema::CompoundScopeRAII Scope(Actions); + AssociatedStmt = ParseStatement(); + EndLoc = Tok.getLocation(); + Directive = Actions.ActOnCompoundStmt(Loc, EndLoc, + AssociatedStmt.get(), + /*isStmtExpr=*/false); + } + ParseOpenMPEndAssumesDirective(Loc); + OMPDirectiveScope.Exit(); + break; + } case OMPD_unknown: default: Diag(Tok, diag::err_omp_unknown_directive); diff --git a/clang/lib/Sema/SemaOpenMP.cpp b/clang/lib/Sema/SemaOpenMP.cpp index 6110e5229b076..9ec2bd9c3b802 100644 --- a/clang/lib/Sema/SemaOpenMP.cpp +++ b/clang/lib/Sema/SemaOpenMP.cpp @@ -3511,7 +3511,8 @@ void SemaOpenMP::ActOnOpenMPAssumesDirective(SourceLocation Loc, auto *AA = OMPAssumeAttr::Create(getASTContext(), llvm::join(Assumptions, ","), Loc); - if (DKind == llvm::omp::Directive::OMPD_begin_assumes) { + if (DKind == llvm::omp::Directive::OMPD_begin_assumes || + DKind == llvm::omp::Directive::OMPD_assume) { OMPAssumeScoped.push_back(AA); return; } diff --git a/clang/test/OpenMP/assume_lambda.cpp b/clang/test/OpenMP/assume_lambda.cpp new file mode 100644 index 0000000000000..a38380ed4482a --- /dev/null +++ b/clang/test/OpenMP/assume_lambda.cpp @@ -0,0 +1,31 @@ +// RUN: %clang_cc1 -fopenmp -x c++ -std=c++11 -ast-print %s | FileCheck %s +// expected-no-diagnostics + +extern int bar(int); + +int foo(int arg) +{ + #pragma omp assume no_openmp_routines + { + auto fn = [](int x) { return bar(x); }; +// CHECK: auto fn = [](int x) { + return fn(5); + } +} + +class C { +public: + int foo(int a); +}; + +// We're really just checking that this parses. All the assumptions are thrown +// away immediately for now. +int C::foo(int a) +{ + #pragma omp assume holds(sizeof(T) == 8) absent(parallel) + { + auto fn = [](int x) { return bar(x); }; +// CHECK: auto fn = [](int x) { + return fn(5); + } +} \ No newline at end of file diff --git a/clang/test/OpenMP/assume_messages.c b/clang/test/OpenMP/assume_messages.c new file mode 100644 index 0000000000000..33c1c6f7c51e7 --- /dev/null +++ b/clang/test/OpenMP/assume_messages.c @@ -0,0 +1,23 @@ +// RUN: %clang_cc1 -triple=x86_64-linux-gnu -verify -fopenmp -x c -std=c99 %s +// RUN: %clang_cc1 -triple=x86_64-linux-gnu -verify -fopenmp-simd -x c -std=c99 %s + +#pragma omp assume no_openmp // expected-error {{unexpected OpenMP directive '#pragma omp assume'}} + +void foo(void) { + #pragma omp assume hold(1==1) // expected-warning {{valid assume clauses start with 'ext_', 'absent', 'contains', 'holds', 'no_openmp', 'no_openmp_routines', 'no_parallelism'; tokens will be ignored}} expected-note {{the ignored tokens spans until here}} + {} +} + +void bar(void) { + #pragma omp assume absent(target) +} // expected-error {{expected statement}} + +void qux(void) { + #pragma omp assume extra_bits // expected-warning {{valid assume clauses start with 'ext_', 'absent', 'contains', 'holds', 'no_openmp', 'no_openmp_routines', 'no_parallelism'; token will be ignored}} + {} +} + +void quux(void) { + #pragma omp assume ext_spelled_properly + {} +} diff --git a/clang/test/OpenMP/assume_messages_attr.c b/clang/test/OpenMP/assume_messages_attr.c new file mode 100644 index 0000000000000..47504cc6308ea --- /dev/null +++ b/clang/test/OpenMP/assume_messages_attr.c @@ -0,0 +1,23 @@ +// RUN: %clang_cc1 -triple=x86_64-linux-gnu -verify -fopenmp -x c -std=c99 %s +// RUN: %clang_cc1 -triple=x86_64-linux-gnu -verify -fopenmp-simd -x c -std=c99 %s + +[[omp::directive(assume no_openmp)]] // expected-error {{unexpected OpenMP directive '#pragma omp assume'}} + +void foo(void) { + [[omp::directive(assume hold(1==1))]] // expected-warning {{valid assume clauses start with 'ext_', 'absent', 'contains', 'holds', 'no_openmp', 'no_openmp_routines', 'no_parallelism'; tokens will be ignored}} expected-note {{the ignored tokens spans until here}} + {} +} + +void bar(void) { + [[omp::directive(assume absent(target))]] +} // expected-error {{expected statement}} + +void qux(void) { + [[omp::directive(assume extra_bits)]] // expected-warning {{valid assume clauses start with 'ext_', 'absent', 'contains', 'holds', 'no_openmp', 'no_openmp_routines', 'no_parallelism'; token will be ignored}} + {} +} + +void quux(void) { + [[omp::directive(assume ext_spelled_properly)]] + {} +} diff --git a/clang/test/OpenMP/assume_template.cpp b/clang/test/OpenMP/assume_template.cpp new file mode 100644 index 0000000000000..b0591bffb20a6 --- /dev/null +++ b/clang/test/OpenMP/assume_template.cpp @@ -0,0 +1,42 @@ +// RUN: %clang_cc1 -verify -fopenmp -ast-print %s | FileCheck %s +// RUN: %clang_cc1 -fopenmp -x c++ -std=c++11 -emit-pch -o %t %s +// RUN: %clang_cc1 -fopenmp -std=c++11 -include-pch %t -verify %s -ast-print | FileCheck %s +// expected-no-diagnostics + +#ifndef HEADER +#define HEADER + +extern int qux(int); + +template<typename T> +int foo(T arg) +{ + #pragma omp assume no_openmp_routines + { + auto fn = [](int x) { return qux(x); }; +// CHECK: auto fn = [](int x) { + return fn(5); + } +} + +template<typename T> +class C { + T m; + +public: + T bar(T a); +}; + +// We're really just checking this parses. All the assumptions are thrown +// away immediately for now. +template<typename T> +T C<T>::bar(T a) +{ + #pragma omp assume holds(sizeof(T) == 8) absent(parallel) + { + return (T)qux((int)a); +// CHECK: return (T)qux((int)a); + } +} + +#endif \ No newline at end of file diff --git a/llvm/include/llvm/Frontend/OpenMP/OMP.td b/llvm/include/llvm/Frontend/OpenMP/OMP.td index e91169e8da1aa..3660917e3e176 100644 --- a/llvm/include/llvm/Frontend/OpenMP/OMP.td +++ b/llvm/include/llvm/Frontend/OpenMP/OMP.td @@ -2089,6 +2089,9 @@ def OMP_Scan : Directive<"scan"> { ]; let association = AS_Separating; } +def OMP_Assume : Directive<"assume"> { + let association = AS_Block; +} def OMP_Assumes : Directive<"assumes"> { let association = AS_None; } _______________________________________________ cfe-commits mailing list cfe-commits@lists.llvm.org https://lists.llvm.org/cgi-bin/mailman/listinfo/cfe-commits