Skip to content

Commit

Permalink
[OpenMP] OpenMP 5.1 "assume" directive parsing support
Browse files Browse the repository at this point in the history
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
  • Loading branch information
jtb20 committed Jun 13, 2024
1 parent 525c25a commit c06ce37
Show file tree
Hide file tree
Showing 7 changed files with 147 additions and 1 deletion.
22 changes: 22 additions & 0 deletions clang/lib/Parse/ParseOpenMP.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -2444,6 +2444,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;
Expand Down Expand Up @@ -3023,6 +3024,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);
Expand Down
3 changes: 2 additions & 1 deletion clang/lib/Sema/SemaOpenMP.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -3512,7 +3512,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;
}
Expand Down
31 changes: 31 additions & 0 deletions clang/test/OpenMP/assume_lambda.cpp
Original file line number Diff line number Diff line change
@@ -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);
}
}
23 changes: 23 additions & 0 deletions clang/test/OpenMP/assume_messages.c
Original file line number Diff line number Diff line change
@@ -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
{}
}
23 changes: 23 additions & 0 deletions clang/test/OpenMP/assume_messages_attr.c
Original file line number Diff line number Diff line change
@@ -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)]]
{}
}
42 changes: 42 additions & 0 deletions clang/test/OpenMP/assume_template.cpp
Original file line number Diff line number Diff line change
@@ -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
4 changes: 4 additions & 0 deletions llvm/include/llvm/Frontend/OpenMP/OMP.td
Original file line number Diff line number Diff line change
Expand Up @@ -510,6 +510,10 @@ def OMP_EndAssumes : Directive<"end assumes"> {
let association = AS_Delimited;
let category = OMP_Assumes.category;
}
def OMP_Assume : Directive<"assume"> {
let association = AS_Block;
let category = CA_Informational;
}
def OMP_Atomic : Directive<"atomic"> {
let allowedClauses = [
VersionedClause<OMPC_Capture>,
Expand Down

0 comments on commit c06ce37

Please sign in to comment.