Skip to content

[OpenMP] Allow begin/end declare variant in executable context #139344

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Merged
merged 1 commit into from
May 12, 2025
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
3 changes: 3 additions & 0 deletions clang/include/clang/Parse/Parser.h
Original file line number Diff line number Diff line change
Expand Up @@ -3537,6 +3537,9 @@ class Parser : public CodeCompletionHandler {
DeclarationName &Name,
AccessSpecifier AS = AS_none);

/// Parses 'omp begin declare variant' directive.
bool ParseOpenMPDeclareBeginVariantDirective(SourceLocation Loc);

/// Tries to parse cast part of OpenMP array shaping operation:
/// '[' expression ']' { '[' expression ']' } ')'.
bool tryParseOpenMPArrayShapingCastPart();
Expand Down
158 changes: 92 additions & 66 deletions clang/lib/Parse/ParseOpenMP.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -668,6 +668,72 @@ TypeResult Parser::parseOpenMPDeclareMapperVarDecl(SourceRange &Range,
DeclaratorInfo);
}

/// Parses 'omp begin declare variant' directive.
// The syntax is:
// { #pragma omp begin declare variant clause }
// <function-declaration-or-definition-sequence>
// { #pragma omp end declare variant }
//
bool Parser::ParseOpenMPDeclareBeginVariantDirective(SourceLocation Loc) {
OMPTraitInfo *ParentTI =
Actions.OpenMP().getOMPTraitInfoForSurroundingScope();
ASTContext &ASTCtx = Actions.getASTContext();
OMPTraitInfo &TI = ASTCtx.getNewOMPTraitInfo();
if (parseOMPDeclareVariantMatchClause(Loc, TI, ParentTI)) {
while (!SkipUntil(tok::annot_pragma_openmp_end, Parser::StopBeforeMatch))
;
// Skip the last annot_pragma_openmp_end.
(void)ConsumeAnnotationToken();
return true;
}

// Skip last tokens.
skipUntilPragmaOpenMPEnd(OMPD_begin_declare_variant);

ParsingOpenMPDirectiveRAII NormalScope(*this, /*Value=*/false);

VariantMatchInfo VMI;
TI.getAsVariantMatchInfo(ASTCtx, VMI);

std::function<void(StringRef)> DiagUnknownTrait = [this,
Loc](StringRef ISATrait) {
// TODO Track the selector locations in a way that is accessible here
// to improve the diagnostic location.
Diag(Loc, diag::warn_unknown_declare_variant_isa_trait) << ISATrait;
};
TargetOMPContext OMPCtx(
ASTCtx, std::move(DiagUnknownTrait),
/* CurrentFunctionDecl */ nullptr,
/* ConstructTraits */ ArrayRef<llvm::omp::TraitProperty>(),
Actions.OpenMP().getOpenMPDeviceNum());

if (isVariantApplicableInContext(VMI, OMPCtx,
/*DeviceOrImplementationSetOnly=*/true)) {
Actions.OpenMP().ActOnOpenMPBeginDeclareVariant(Loc, TI);
return false;
}

// Elide all the code till the matching end declare variant was found.
unsigned Nesting = 1;
SourceLocation DKLoc;
OpenMPDirectiveKind DK = OMPD_unknown;
do {
DKLoc = Tok.getLocation();
DK = parseOpenMPDirectiveKind(*this);
if (DK == OMPD_end_declare_variant)
--Nesting;
else if (DK == OMPD_begin_declare_variant)
++Nesting;
if (!Nesting || isEofOrEom())
break;
ConsumeAnyToken();
} while (true);

parseOMPEndDirective(OMPD_begin_declare_variant, OMPD_end_declare_variant, DK,
Loc, DKLoc, /* SkipUntilOpenMPEnd */ true);
return false;
}

namespace {
/// RAII that recreates function context for correct parsing of clauses of
/// 'declare simd' construct.
Expand Down Expand Up @@ -2244,79 +2310,23 @@ Parser::DeclGroupPtrTy Parser::ParseOpenMPDeclarativeDirectiveWithExtDecl(
break;
}
case OMPD_begin_declare_variant: {
// The syntax is:
// { #pragma omp begin declare variant clause }
// <function-declaration-or-definition-sequence>
// { #pragma omp end declare variant }
//
ConsumeToken();
OMPTraitInfo *ParentTI =
Actions.OpenMP().getOMPTraitInfoForSurroundingScope();
ASTContext &ASTCtx = Actions.getASTContext();
OMPTraitInfo &TI = ASTCtx.getNewOMPTraitInfo();
if (parseOMPDeclareVariantMatchClause(Loc, TI, ParentTI)) {
while (!SkipUntil(tok::annot_pragma_openmp_end, Parser::StopBeforeMatch))
;
if (!ParseOpenMPDeclareBeginVariantDirective(Loc)) {
// Skip the last annot_pragma_openmp_end.
(void)ConsumeAnnotationToken();
break;
if (!isEofOrEom())
ConsumeAnnotationToken();
}

// Skip last tokens.
skipUntilPragmaOpenMPEnd(OMPD_begin_declare_variant);

ParsingOpenMPDirectiveRAII NormalScope(*this, /*Value=*/false);

VariantMatchInfo VMI;
TI.getAsVariantMatchInfo(ASTCtx, VMI);

std::function<void(StringRef)> DiagUnknownTrait =
[this, Loc](StringRef ISATrait) {
// TODO Track the selector locations in a way that is accessible here
// to improve the diagnostic location.
Diag(Loc, diag::warn_unknown_declare_variant_isa_trait) << ISATrait;
};
TargetOMPContext OMPCtx(
ASTCtx, std::move(DiagUnknownTrait),
/* CurrentFunctionDecl */ nullptr,
/* ConstructTraits */ ArrayRef<llvm::omp::TraitProperty>(),
Actions.OpenMP().getOpenMPDeviceNum());

if (isVariantApplicableInContext(VMI, OMPCtx,
/*DeviceOrImplementationSetOnly=*/true)) {
Actions.OpenMP().ActOnOpenMPBeginDeclareVariant(Loc, TI);
break;
}

// Elide all the code till the matching end declare variant was found.
unsigned Nesting = 1;
SourceLocation DKLoc;
OpenMPDirectiveKind DK = OMPD_unknown;
do {
DKLoc = Tok.getLocation();
DK = parseOpenMPDirectiveKind(*this);
if (DK == OMPD_end_declare_variant)
--Nesting;
else if (DK == OMPD_begin_declare_variant)
++Nesting;
if (!Nesting || isEofOrEom())
break;
ConsumeAnyToken();
} while (true);

parseOMPEndDirective(OMPD_begin_declare_variant, OMPD_end_declare_variant,
DK, Loc, DKLoc, /* SkipUntilOpenMPEnd */ true);
if (isEofOrEom())
return nullptr;
break;
return nullptr;
}
case OMPD_end_declare_variant: {
ConsumeToken();
if (Actions.OpenMP().isInOpenMPDeclareVariantScope())
Actions.OpenMP().ActOnOpenMPEndDeclareVariant();
else
Diag(Loc, diag::err_expected_begin_declare_variant);
ConsumeToken();
break;
// Skip the last annot_pragma_openmp_end.
ConsumeAnnotationToken();
return nullptr;
}
case OMPD_declare_variant:
case OMPD_declare_simd: {
Expand Down Expand Up @@ -3028,12 +3038,28 @@ StmtResult Parser::ParseOpenMPDeclarativeOrExecutableDirective(
Actions.OpenMP().ActOnFinishedOpenMPDeclareTargetContext(DTCI);
break;
}
case OMPD_begin_declare_variant: {
ConsumeToken();
if (!ParseOpenMPDeclareBeginVariantDirective(Loc)) {
// Skip the last annot_pragma_openmp_end.
if (!isEofOrEom())
ConsumeAnnotationToken();
}
return Directive;
}
case OMPD_end_declare_variant: {
ConsumeToken();
if (Actions.OpenMP().isInOpenMPDeclareVariantScope())
Actions.OpenMP().ActOnOpenMPEndDeclareVariant();
else
Diag(Loc, diag::err_expected_begin_declare_variant);
ConsumeAnnotationToken();
break;
}
case OMPD_declare_simd:
case OMPD_begin_declare_target:
case OMPD_end_declare_target:
case OMPD_requires:
case OMPD_begin_declare_variant:
case OMPD_end_declare_variant:
case OMPD_declare_variant:
Diag(Tok, diag::err_omp_unexpected_directive)
<< 1 << getOpenMPDirectiveName(DKind, OMPVersion);
Expand Down
23 changes: 23 additions & 0 deletions clang/test/OpenMP/begin_declare_variant_executable_scope.c
Original file line number Diff line number Diff line change
@@ -0,0 +1,23 @@
// RUN: %clang_cc1 -triple=x86_64-pc-win32 -verify -fopenmp -x c -std=c99 -fms-extensions -Wno-pragma-pack %s
// RUN: %clang_cc1 -triple=x86_64-pc-win32 -verify -fopenmp-simd -x c -std=c99 -fms-extensions -Wno-pragma-pack %s

// expected-no-diagnostics

#pragma omp begin declare variant match(implementation={vendor(ibm)})
void f(int);
#pragma omp end declare variant

#pragma omp begin declare variant match(implementation={vendor(llvm)})
void f(void);
#pragma omp end declare variant

int main() {
#pragma omp begin declare variant match(implementation={vendor(ibm)})
int i = 0;
f(i);
#pragma omp end declare variant

#pragma omp begin declare variant match(implementation={vendor(llvm)})
f();
#pragma omp end declare variant
}
9 changes: 4 additions & 5 deletions clang/test/OpenMP/begin_declare_variant_messages.c
Original file line number Diff line number Diff line change
Expand Up @@ -16,8 +16,7 @@
#pragma omp variant begin // expected-error {{expected an OpenMP directive}}
#pragma omp declare variant end // expected-error {{function declaration is expected after 'declare variant' directive}}
#pragma omp begin declare variant // omp50-error {{expected 'match' clause on 'omp declare variant' directive}} omp51-error {{expected 'match', 'adjust_args', or 'append_args' clause on 'omp declare variant' directive}}
#pragma omp end declare variant
// TODO: Issue an error message
#pragma omp end declare variant // expected-error {{'#pragma omp end declare variant' with no matching '#pragma omp begin declare variant'}}
#pragma omp end declare variant // expected-error {{'#pragma omp end declare variant' with no matching '#pragma omp begin declare variant'}}
#pragma omp end declare variant // expected-error {{'#pragma omp end declare variant' with no matching '#pragma omp begin declare variant'}}
#pragma omp end declare variant // expected-error {{'#pragma omp end declare variant' with no matching '#pragma omp begin declare variant'}}
Expand All @@ -27,11 +26,11 @@ int foo(void);
const int var;

#pragma omp begin declare variant // omp50-error {{expected 'match' clause on 'omp declare variant' directive}} omp51-error {{expected 'match', 'adjust_args', or 'append_args' clause on 'omp declare variant' directive}}
#pragma omp end declare variant
#pragma omp end declare variant // expected-error {{'#pragma omp end declare variant' with no matching '#pragma omp begin declare variant'}}
#pragma omp begin declare variant xxx // omp50-error {{expected 'match' clause on 'omp declare variant' directive}} omp51-error {{expected 'match', 'adjust_args', or 'append_args' clause on 'omp declare variant' directive}}
#pragma omp end declare variant
#pragma omp end declare variant // expected-error {{'#pragma omp end declare variant' with no matching '#pragma omp begin declare variant'}}
#pragma omp begin declare variant match // expected-error {{expected '(' after 'match'}}
#pragma omp end declare variant
#pragma omp end declare variant // expected-error {{'#pragma omp end declare variant' with no matching '#pragma omp begin declare variant'}}
#pragma omp begin declare variant match( // expected-error {{expected ')'}} expected-warning {{expected identifier or string literal describing a context set; set skipped}} expected-note {{context set options are: 'construct' 'device' 'target_device' 'implementation' 'user'}} expected-note {{the ignored set spans until here}} expected-note {{to match this '('}}
#pragma omp end declare variant
#pragma omp begin declare variant match() // expected-warning {{expected identifier or string literal describing a context set; set skipped}} expected-note {{context set options are: 'construct' 'device' 'target_device' 'implementation' 'user'}} expected-note {{the ignored set spans until here}}
Expand Down