diff --git a/clang/include/clang/Basic/Attr.td b/clang/include/clang/Basic/Attr.td --- a/clang/include/clang/Basic/Attr.td +++ b/clang/include/clang/Basic/Attr.td @@ -3690,6 +3690,8 @@ let Args = [ ExprArgument<"VariantFuncRef">, OMPTraitInfoArgument<"TraitInfos">, + VariadicExprArgument<"AdjustArgsNothing">, + VariadicExprArgument<"AdjustArgsNeedDevicePtr"> ]; let AdditionalMembers = [{ OMPTraitInfo &getTraitInfo() { return *traitInfos; } diff --git a/clang/include/clang/Basic/DiagnosticParseKinds.td b/clang/include/clang/Basic/DiagnosticParseKinds.td --- a/clang/include/clang/Basic/DiagnosticParseKinds.td +++ b/clang/include/clang/Basic/DiagnosticParseKinds.td @@ -1357,7 +1357,8 @@ def err_omp_mapper_expected_declarator : Error< "expected declarator on 'omp declare mapper' directive">; def err_omp_declare_variant_wrong_clause : Error< - "expected '%0' clause on 'omp declare variant' directive">; + "expected %select{'match'|'match' or 'adjust_args'}0 clause on " + "'omp declare variant' directive">; def err_omp_declare_variant_duplicate_nested_trait : Error< "nested OpenMP context selector contains duplicated trait '%0'" " in selector '%1' and set '%2' with different score">; diff --git a/clang/include/clang/Basic/DiagnosticSemaKinds.td b/clang/include/clang/Basic/DiagnosticSemaKinds.td --- a/clang/include/clang/Basic/DiagnosticSemaKinds.td +++ b/clang/include/clang/Basic/DiagnosticSemaKinds.td @@ -10817,6 +10817,10 @@ def note_omp_directive_here : Note<"'%0' directive found here">; def err_omp_instantiation_not_supported : Error<"instantiation of '%0' not supported yet">; +def err_omp_adjust_arg_multiple_clauses : Error< + "'adjust_arg' argument %0 used in multiple clauses">; +def err_omp_clause_requires_dispatch_construct : Error< + "'%0' clause requires 'dispatch' context selector">; } // end of OpenMP category let CategoryName = "Related Result Type Issue" in { diff --git a/clang/include/clang/Basic/OpenMPKinds.h b/clang/include/clang/Basic/OpenMPKinds.h --- a/clang/include/clang/Basic/OpenMPKinds.h +++ b/clang/include/clang/Basic/OpenMPKinds.h @@ -167,6 +167,13 @@ OMPC_REDUCTION_unknown, }; +/// OpenMP adjust-op kinds for 'adjust_args' clause. +enum OpenMPAdjustArgsOpKind { +#define OPENMP_ADJUST_ARGS_KIND(Name) OMPC_ADJUST_ARGS_##Name, +#include "clang/Basic/OpenMPKinds.def" + OMPC_ADJUST_ARGS_unknown, +}; + unsigned getOpenMPSimpleClauseType(OpenMPClauseKind Kind, llvm::StringRef Str, const LangOptions &LangOpts); const char *getOpenMPSimpleClauseTypeName(OpenMPClauseKind Kind, unsigned Type); diff --git a/clang/include/clang/Basic/OpenMPKinds.def b/clang/include/clang/Basic/OpenMPKinds.def --- a/clang/include/clang/Basic/OpenMPKinds.def +++ b/clang/include/clang/Basic/OpenMPKinds.def @@ -59,6 +59,9 @@ #ifndef OPENMP_REDUCTION_MODIFIER #define OPENMP_REDUCTION_MODIFIER(Name) #endif +#ifndef OPENMP_ADJUST_ARGS_KIND +#define OPENMP_ADJUST_ARGS_KIND(Name) +#endif // Static attributes for 'schedule' clause. OPENMP_SCHEDULE_KIND(static) @@ -149,6 +152,11 @@ OPENMP_REDUCTION_MODIFIER(inscan) OPENMP_REDUCTION_MODIFIER(task) +// Adjust-op kinds for the 'adjust_args' clause. +OPENMP_ADJUST_ARGS_KIND(nothing) +OPENMP_ADJUST_ARGS_KIND(need_device_ptr) + +#undef OPENMP_ADJUST_ARGS_KIND #undef OPENMP_REDUCTION_MODIFIER #undef OPENMP_DEVICE_MODIFIER #undef OPENMP_ORDER_KIND diff --git a/clang/include/clang/Sema/Sema.h b/clang/include/clang/Sema/Sema.h --- a/clang/include/clang/Sema/Sema.h +++ b/clang/include/clang/Sema/Sema.h @@ -10977,8 +10977,10 @@ /// \param VariantRef Expression that references the variant function, which /// must be used instead of the original one, specified in \p DG. /// \param TI The context traits associated with the function variant. - void ActOnOpenMPDeclareVariantDirective(FunctionDecl *FD, Expr *VariantRef, - OMPTraitInfo &TI, SourceRange SR); + void ActOnOpenMPDeclareVariantDirective( + FunctionDecl *FD, Expr *VariantRef, OMPTraitInfo &TI, + ArrayRef AdjustArgsNothing, + ArrayRef AdjustArgsNeedDevicePtr, SourceRange SR); OMPClause *ActOnOpenMPSingleExprClause(OpenMPClauseKind Kind, Expr *Expr, diff --git a/clang/lib/AST/AttrImpl.cpp b/clang/lib/AST/AttrImpl.cpp --- a/clang/lib/AST/AttrImpl.cpp +++ b/clang/lib/AST/AttrImpl.cpp @@ -195,6 +195,25 @@ OS << ")"; } OS << " match(" << traitInfos << ")"; + + auto PrintExprs = [&OS, &Policy](Expr **Begin, Expr **End) { + for (Expr **I = Begin; I != End; ++I) { + assert(*I && "Expected non-null Stmt"); + if (I != Begin) + OS << ","; + (*I)->printPretty(OS, nullptr, Policy); + } + }; + if (adjustArgsNothing_size()) { + OS << " adjust_args(nothing:"; + PrintExprs(adjustArgsNothing_begin(), adjustArgsNothing_end()); + OS << ")"; + } + if (adjustArgsNeedDevicePtr_size()) { + OS << " adjust_args(need_device_ptr:"; + PrintExprs(adjustArgsNeedDevicePtr_begin(), adjustArgsNeedDevicePtr_end()); + OS << ")"; + } } #include "clang/AST/AttrImpl.inc" diff --git a/clang/lib/Basic/OpenMPKinds.cpp b/clang/lib/Basic/OpenMPKinds.cpp --- a/clang/lib/Basic/OpenMPKinds.cpp +++ b/clang/lib/Basic/OpenMPKinds.cpp @@ -125,6 +125,11 @@ #define OPENMP_REDUCTION_MODIFIER(Name) .Case(#Name, OMPC_REDUCTION_##Name) #include "clang/Basic/OpenMPKinds.def" .Default(OMPC_REDUCTION_unknown); + case OMPC_adjust_args: + return llvm::StringSwitch(Str) +#define OPENMP_ADJUST_ARGS_KIND(Name) .Case(#Name, OMPC_ADJUST_ARGS_##Name) +#include "clang/Basic/OpenMPKinds.def" + .Default(OMPC_ADJUST_ARGS_unknown); case OMPC_unknown: case OMPC_threadprivate: case OMPC_if: @@ -369,6 +374,16 @@ #include "clang/Basic/OpenMPKinds.def" } llvm_unreachable("Invalid OpenMP 'reduction' clause modifier"); + case OMPC_adjust_args: + switch (Type) { + case OMPC_ADJUST_ARGS_unknown: + return "unknown"; +#define OPENMP_ADJUST_ARGS_KIND(Name) \ + case OMPC_ADJUST_ARGS_##Name: \ + return #Name; +#include "clang/Basic/OpenMPKinds.def" + } + llvm_unreachable("Invalid OpenMP 'adjust_args' clause kind"); case OMPC_unknown: case OMPC_threadprivate: case OMPC_if: diff --git a/clang/lib/CodeGen/CGStmtOpenMP.cpp b/clang/lib/CodeGen/CGStmtOpenMP.cpp --- a/clang/lib/CodeGen/CGStmtOpenMP.cpp +++ b/clang/lib/CodeGen/CGStmtOpenMP.cpp @@ -5989,6 +5989,7 @@ case OMPC_nocontext: case OMPC_filter: case OMPC_when: + case OMPC_adjust_args: llvm_unreachable("Clause is not allowed in 'omp atomic'."); } } diff --git a/clang/lib/Parse/ParseOpenMP.cpp b/clang/lib/Parse/ParseOpenMP.cpp --- a/clang/lib/Parse/ParseOpenMP.cpp +++ b/clang/lib/Parse/ParseOpenMP.cpp @@ -1402,21 +1402,69 @@ OMPTraitInfo *ParentTI = Actions.getOMPTraitInfoForSurroundingScope(); ASTContext &ASTCtx = Actions.getASTContext(); OMPTraitInfo &TI = ASTCtx.getNewOMPTraitInfo(); - if (parseOMPDeclareVariantMatchClause(Loc, TI, ParentTI)) - return; + SmallVector AdjustNothing; + SmallVector AdjustNeedDevicePtr; + + // At least one clause is required. + if (Tok.is(tok::annot_pragma_openmp_end)) { + Diag(Tok.getLocation(), diag::err_omp_declare_variant_wrong_clause) + << (getLangOpts().OpenMP < 51 ? 0 : 1); + } + + bool IsError = false; + while (Tok.isNot(tok::annot_pragma_openmp_end)) { + OpenMPClauseKind CKind = Tok.isAnnotation() + ? OMPC_unknown + : getOpenMPClauseKind(PP.getSpelling(Tok)); + if (!isAllowedClauseForDirective(OMPD_declare_variant, CKind, + getLangOpts().OpenMP)) { + Diag(Tok.getLocation(), diag::err_omp_declare_variant_wrong_clause) + << (getLangOpts().OpenMP < 51 ? 0 : 1); + IsError = true; + } + if (!IsError) { + switch (CKind) { + case OMPC_match: + IsError = parseOMPDeclareVariantMatchClause(Loc, TI, ParentTI); + break; + case OMPC_adjust_args: { + ConsumeToken(); + Parser::OpenMPVarListDataTy Data; + SmallVector Vars; + IsError = ParseOpenMPVarList(OMPD_declare_variant, OMPC_adjust_args, + Vars, Data); + if (!IsError) + llvm::append_range(Data.ExtraModifier == OMPC_ADJUST_ARGS_nothing + ? AdjustNothing + : AdjustNeedDevicePtr, + Vars); + break; + } + default: + llvm_unreachable("Unexpected clause for declare variant."); + } + } + if (IsError) { + while (!SkipUntil(tok::annot_pragma_openmp_end, StopBeforeMatch)) + ; + // Skip the last annot_pragma_openmp_end. + (void)ConsumeAnnotationToken(); + return; + } + // Skip ',' if any. + if (Tok.is(tok::comma)) + ConsumeToken(); + } Optional> DeclVarData = Actions.checkOpenMPDeclareVariantFunction( Ptr, AssociatedFunction.get(), TI, SourceRange(Loc, Tok.getLocation())); - // Skip last tokens. - while (Tok.isNot(tok::annot_pragma_openmp_end)) - ConsumeAnyToken(); if (DeclVarData && !TI.Sets.empty()) Actions.ActOnOpenMPDeclareVariantDirective( - DeclVarData->first, DeclVarData->second, TI, - SourceRange(Loc, Tok.getLocation())); + DeclVarData->first, DeclVarData->second, TI, AdjustNothing, + AdjustNeedDevicePtr, SourceRange(Loc, Tok.getLocation())); // Skip the last annot_pragma_openmp_end. (void)ConsumeAnnotationToken(); @@ -1431,24 +1479,15 @@ : getOpenMPClauseKind(PP.getSpelling(Tok)); if (CKind != OMPC_match) { Diag(Tok.getLocation(), diag::err_omp_declare_variant_wrong_clause) - << getOpenMPClauseName(OMPC_match); - while (!SkipUntil(tok::annot_pragma_openmp_end, Parser::StopBeforeMatch)) - ; - // Skip the last annot_pragma_openmp_end. - (void)ConsumeAnnotationToken(); + << (getLangOpts().OpenMP < 51 ? 0 : 1); return true; } (void)ConsumeToken(); // Parse '('. BalancedDelimiterTracker T(*this, tok::l_paren, tok::annot_pragma_openmp_end); if (T.expectAndConsume(diag::err_expected_lparen_after, - getOpenMPClauseName(OMPC_match).data())) { - while (!SkipUntil(tok::annot_pragma_openmp_end, StopBeforeMatch)) - ; - // Skip the last annot_pragma_openmp_end. - (void)ConsumeAnnotationToken(); + getOpenMPClauseName(OMPC_match).data())) return true; - } // Parse inner context selectors. parseOMPContextSelectors(Loc, TI); @@ -2029,8 +2068,13 @@ OMPTraitInfo *ParentTI = Actions.getOMPTraitInfoForSurroundingScope(); ASTContext &ASTCtx = Actions.getASTContext(); OMPTraitInfo &TI = ASTCtx.getNewOMPTraitInfo(); - if (parseOMPDeclareVariantMatchClause(Loc, TI, ParentTI)) + if (parseOMPDeclareVariantMatchClause(Loc, TI, ParentTI)) { + while (!SkipUntil(tok::annot_pragma_openmp_end, Parser::StopBeforeMatch)) + ; + // Skip the last annot_pragma_openmp_end. + (void)ConsumeAnnotationToken(); break; + } // Skip last tokens. skipUntilPragmaOpenMPEnd(OMPD_begin_declare_variant); @@ -4100,6 +4144,23 @@ SkipUntil(tok::comma, tok::r_paren, tok::annot_pragma_openmp_end, StopBeforeMatch); } + } else if (Kind == OMPC_adjust_args) { + // Handle adjust-op for adjust_args clause. + ColonProtectionRAIIObject ColonRAII(*this); + Data.ExtraModifier = getOpenMPSimpleClauseType( + Kind, Tok.is(tok::identifier) ? PP.getSpelling(Tok) : "", + getLangOpts()); + Data.ExtraModifierLoc = Tok.getLocation(); + if (Data.ExtraModifier == OMPC_ADJUST_ARGS_unknown) { + SkipUntil(tok::colon, tok::r_paren, tok::annot_pragma_openmp_end, + StopBeforeMatch); + } else { + ConsumeToken(); + if (Tok.is(tok::colon)) + Data.ColonLoc = Tok.getLocation(); + ExpectAndConsume(tok::colon, diag::warn_pragma_expected_colon, + "adjust-op"); + } } bool IsComma = @@ -4107,7 +4168,9 @@ Kind != OMPC_in_reduction && Kind != OMPC_depend && Kind != OMPC_map) || (Kind == OMPC_reduction && !InvalidReductionId) || (Kind == OMPC_map && Data.ExtraModifier != OMPC_MAP_unknown) || - (Kind == OMPC_depend && Data.ExtraModifier != OMPC_DEPEND_unknown); + (Kind == OMPC_depend && Data.ExtraModifier != OMPC_DEPEND_unknown) || + (Kind == OMPC_adjust_args && + Data.ExtraModifier != OMPC_ADJUST_ARGS_unknown); const bool MayHaveTail = (Kind == OMPC_linear || Kind == OMPC_aligned); while (IsComma || (Tok.isNot(tok::r_paren) && Tok.isNot(tok::colon) && Tok.isNot(tok::annot_pragma_openmp_end))) { diff --git a/clang/lib/Sema/SemaOpenMP.cpp b/clang/lib/Sema/SemaOpenMP.cpp --- a/clang/lib/Sema/SemaOpenMP.cpp +++ b/clang/lib/Sema/SemaOpenMP.cpp @@ -6808,7 +6808,9 @@ OMPDeclareVariantScope &DVScope = OMPDeclareVariantScopes.back(); auto *OMPDeclareVariantA = OMPDeclareVariantAttr::CreateImplicit( - Context, VariantFuncRef, DVScope.TI); + Context, VariantFuncRef, DVScope.TI, + /*NothingArgs=*/nullptr, /*NothingArgsSize=*/0, + /*NeedDevicePtrArgs=*/nullptr, /*NeedDevicePtrArgsSize=*/0); for (FunctionDecl *BaseFD : Bases) BaseFD->addAttr(OMPDeclareVariantA); } @@ -7181,12 +7183,66 @@ return std::make_pair(FD, cast(DRE)); } -void Sema::ActOnOpenMPDeclareVariantDirective(FunctionDecl *FD, - Expr *VariantRef, - OMPTraitInfo &TI, - SourceRange SR) { - auto *NewAttr = - OMPDeclareVariantAttr::CreateImplicit(Context, VariantRef, &TI, SR); +void Sema::ActOnOpenMPDeclareVariantDirective( + FunctionDecl *FD, Expr *VariantRef, OMPTraitInfo &TI, + ArrayRef AdjustArgsNothing, + ArrayRef AdjustArgsNeedDevicePtr, SourceRange SR) { + + // OpenMP 5.1 [2.3.5, declare variant directive, Restrictions] + // An adjust_args clause or append_args clause can only be specified if the + // dispatch selector of the construct selector set appears in the match + // clause. + + SmallVector AllAdjustArgs; + llvm::append_range(AllAdjustArgs, AdjustArgsNothing); + llvm::append_range(AllAdjustArgs, AdjustArgsNeedDevicePtr); + + if (!AllAdjustArgs.empty()) { + VariantMatchInfo VMI; + TI.getAsVariantMatchInfo(Context, VMI); + if (!llvm::is_contained( + VMI.ConstructTraits, + llvm::omp::TraitProperty::construct_dispatch_dispatch)) { + Diag(AllAdjustArgs[0]->getExprLoc(), + diag::err_omp_clause_requires_dispatch_construct) + << getOpenMPClauseName(OMPC_adjust_args); + return; + } + } + + // OpenMP 5.1 [2.3.5, declare variant directive, Restrictions] + // Each argument can only appear in a single adjust_args clause for each + // declare variant directive. + llvm::SmallPtrSet AdjustVars; + + for (Expr *E : AllAdjustArgs) { + E = E->IgnoreParenImpCasts(); + if (const auto *DRE = dyn_cast(E)) { + if (const auto *PVD = dyn_cast(DRE->getDecl())) { + const VarDecl *CanonPVD = PVD->getCanonicalDecl(); + if (FD->getNumParams() > PVD->getFunctionScopeIndex() && + FD->getParamDecl(PVD->getFunctionScopeIndex()) + ->getCanonicalDecl() == CanonPVD) { + // It's a parameter of the function, check duplicates. + if (!AdjustVars.insert(CanonPVD).second) { + Diag(DRE->getLocation(), diag::err_omp_adjust_arg_multiple_clauses) + << PVD; + return; + } + continue; + } + } + } + // Anything that is not a function parameter is an error. + Diag(E->getExprLoc(), diag::err_omp_param_or_this_in_clause) << FD << 0; + return; + } + + auto *NewAttr = OMPDeclareVariantAttr::CreateImplicit( + Context, VariantRef, &TI, const_cast(AdjustArgsNothing.data()), + AdjustArgsNothing.size(), + const_cast(AdjustArgsNeedDevicePtr.data()), + AdjustArgsNeedDevicePtr.size(), SR); FD->addAttr(NewAttr); } diff --git a/clang/lib/Sema/SemaTemplateInstantiateDecl.cpp b/clang/lib/Sema/SemaTemplateInstantiateDecl.cpp --- a/clang/lib/Sema/SemaTemplateInstantiateDecl.cpp +++ b/clang/lib/Sema/SemaTemplateInstantiateDecl.cpp @@ -481,7 +481,22 @@ } } - S.ActOnOpenMPDeclareVariantDirective(FD, E, TI, Attr.getRange()); + SmallVector NothingExprs; + SmallVector NeedDevicePtrExprs; + for (Expr *E : Attr.adjustArgsNothing()) { + ExprResult ER = Subst(E); + if (ER.isInvalid()) + continue; + NothingExprs.push_back(ER.get()); + } + for (Expr *E : Attr.adjustArgsNeedDevicePtr()) { + ExprResult ER = Subst(E); + if (ER.isInvalid()) + continue; + NeedDevicePtrExprs.push_back(ER.get()); + } + S.ActOnOpenMPDeclareVariantDirective(FD, E, TI, NothingExprs, + NeedDevicePtrExprs, Attr.getRange()); } static void instantiateDependentAMDGPUFlatWorkGroupSizeAttr( diff --git a/clang/test/OpenMP/declare_variant_clauses_ast_print.cpp b/clang/test/OpenMP/declare_variant_clauses_ast_print.cpp new file mode 100644 --- /dev/null +++ b/clang/test/OpenMP/declare_variant_clauses_ast_print.cpp @@ -0,0 +1,107 @@ +//RUN: %clang_cc1 -triple x86_64-pc-linux-gnu -fopenmp -fopenmp-version=51 \ +//RUN: -x c++ -std=c++14 -fexceptions -fcxx-exceptions \ +//RUN: -Wno-source-uses-openmp -Wno-openmp-clauses \ +//RUN: -fsyntax-only -verify -o - %s + +//RUN: %clang_cc1 -triple x86_64-pc-windows-msvc -fopenmp -fopenmp-version=51 \ +//RUN: -x c++ -std=c++14 -fexceptions -fcxx-exceptions \ +//RUN: -Wno-source-uses-openmp -Wno-openmp-clauses \ +//RUN: -fsyntax-only -verify -o - %s + +//RUN: %clang_cc1 -triple x86_64-pc-linux-gnu -fopenmp -fopenmp-version=51 \ +//RUN: -x c++ -std=c++14 -fexceptions -fcxx-exceptions \ +//RUN: -Wno-source-uses-openmp -Wno-openmp-clauses \ +//RUN: -emit-pch -o %t %s + +// expected-no-diagnostics + +//RUN: %clang_cc1 -triple x86_64-pc-linux-gnu -fopenmp -fopenmp-version=51 \ +//RUN: -x c++ -std=c++14 -fexceptions -fcxx-exceptions \ +//RUN: -Wno-source-uses-openmp -Wno-openmp-clauses \ +//RUN: -ast-print %s | FileCheck %s --check-prefix=PRINT + +//RUN: %clang_cc1 -triple x86_64-pc-linux-gnu -fopenmp -fopenmp-version=51 \ +//RUN: -x c++ -std=c++14 -fexceptions -fcxx-exceptions \ +//RUN: -Wno-source-uses-openmp -Wno-openmp-clauses \ +//RUN: -ast-dump %s | FileCheck %s --check-prefix=DUMP + +//RUN: %clang_cc1 -triple x86_64-pc-linux-gnu -fopenmp -fopenmp-version=51 \ +//RUN: -x c++ -std=c++14 -fexceptions -fcxx-exceptions \ +//RUN: -Wno-source-uses-openmp -Wno-openmp-clauses \ +//RUN: -include-pch %t -ast-print %s | FileCheck %s --check-prefix=PRINT + +//RUN: %clang_cc1 -triple x86_64-pc-linux-gnu -fopenmp -fopenmp-version=51 \ +//RUN: -x c++ -std=c++14 -fexceptions -fcxx-exceptions \ +//RUN: -Wno-source-uses-openmp -Wno-openmp-clauses \ +//RUN: -include-pch %t -ast-dump-all %s | FileCheck %s --check-prefix=DUMP + +#ifndef HEADER +#define HEADER + +void foo_v1(float *AAA, float *BBB, int *I) {return;} +void foo_v2(float *AAA, float *BBB, int *I) {return;} +void foo_v3(float *AAA, float *BBB, int *I) {return;} + +//DUMP: FunctionDecl{{.*}} foo 'void (float *, float *, int *)' +//DUMP: OMPDeclareVariantAttr{{.*}}device={arch(x86, x86_64)} +//DUMP: DeclRefExpr{{.*}}Function{{.*}}foo_v3 +//DUMP: DeclRefExpr{{.*}}ParmVar{{.*}}'I' +//DUMP: DeclRefExpr{{.*}}ParmVar{{.*}}'BBB' +//DUMP: OMPDeclareVariantAttr{{.*}}device={arch(ppc)} +//DUMP: DeclRefExpr{{.*}}Function{{.*}}foo_v2 +//DUMP: DeclRefExpr{{.*}}ParmVar{{.*}}'AAA' +//DUMP: OMPDeclareVariantAttr{{.*}}device={arch(arm)} +//DUMP: DeclRefExpr{{.*}}Function{{.*}}foo_v1 +//DUMP: DeclRefExpr{{.*}}ParmVar{{.*}}'AAA' +//DUMP: DeclRefExpr{{.*}}ParmVar{{.*}}'BBB' +//PRINT: #pragma omp declare variant(foo_v3) match(construct={dispatch}, device={arch(x86, x86_64)}) adjust_args(nothing:I) adjust_args(need_device_ptr:BBB) + +//PRINT: #pragma omp declare variant(foo_v2) match(construct={dispatch}, device={arch(ppc)}) adjust_args(need_device_ptr:AAA) + +//PRINT: omp declare variant(foo_v1) match(construct={dispatch}, device={arch(arm)}) adjust_args(need_device_ptr:AAA,BBB) + +#pragma omp declare variant(foo_v1) \ + match(construct={dispatch}, device={arch(arm)}) \ + adjust_args(need_device_ptr:AAA,BBB) + +#pragma omp declare variant(foo_v2) \ + match(construct={dispatch}, device={arch(ppc)}), \ + adjust_args(need_device_ptr:AAA) + +#pragma omp declare variant(foo_v3) \ + adjust_args(need_device_ptr:BBB) adjust_args(nothing:I) \ + match(construct={dispatch}, device={arch(x86,x86_64)}) + +void foo(float *AAA, float *BBB, int *I) {return;} + +void Foo_Var(float *AAA, float *BBB) {return;} + +#pragma omp declare variant(Foo_Var) \ + match(construct={dispatch}, device={arch(x86_64)}) \ + adjust_args(need_device_ptr:AAA) adjust_args(nothing:BBB) +template +void Foo(T *AAA, T *BBB) {return;} + +//PRINT: #pragma omp declare variant(Foo_Var) match(construct={dispatch}, device={arch(x86_64)}) adjust_args(nothing:BBB) adjust_args(need_device_ptr:AAA) +//DUMP: FunctionDecl{{.*}} Foo 'void (T *, T *)' +//DUMP: OMPDeclareVariantAttr{{.*}}device={arch(x86_64)} +//DUMP: DeclRefExpr{{.*}}Function{{.*}}Foo_Var +//DUMP: DeclRefExpr{{.*}}ParmVar{{.*}}'BBB' +//DUMP: DeclRefExpr{{.*}}ParmVar{{.*}}'AAA' +// +//DUMP: FunctionDecl{{.*}} Foo 'void (float *, float *)' +//DUMP: OMPDeclareVariantAttr{{.*}}device={arch(x86_64)} +//DUMP: DeclRefExpr{{.*}}Function{{.*}}Foo_Var +//DUMP: DeclRefExpr{{.*}}ParmVar{{.*}}'BBB' +//DUMP: DeclRefExpr{{.*}}ParmVar{{.*}}'AAA' + +void func() +{ + float *A; + float *B; + + //#pragma omp dispatch + Foo(A, B); +} + +#endif // HEADER diff --git a/clang/test/OpenMP/declare_variant_clauses_messages.cpp b/clang/test/OpenMP/declare_variant_clauses_messages.cpp new file mode 100644 --- /dev/null +++ b/clang/test/OpenMP/declare_variant_clauses_messages.cpp @@ -0,0 +1,47 @@ +// RUN: %clang_cc1 -verify -fopenmp -fopenmp-version=51 -DOMP51 -std=c++11 -o - %s + +// RUN: %clang_cc1 -verify -fopenmp -fopenmp-version=50 -DOMP50 -std=c++11 -o - %s + +int Other; + +void foo_v1(float *AAA, float *BBB, int *I) { return; } +void foo_v2(float *AAA, float *BBB, int *I) { return; } +void foo_v3(float *AAA, float *BBB, int *I) { return; } + +#ifdef OMP51 +// expected-error@+3 {{'adjust_arg' argument 'AAA' used in multiple clauses}} +#pragma omp declare variant(foo_v1) \ + match(construct={dispatch}, device={arch(arm)}) \ + adjust_args(need_device_ptr:AAA,BBB) adjust_args(need_device_ptr:AAA) + +// expected-error@+3 {{'adjust_arg' argument 'AAA' used in multiple clauses}} +#pragma omp declare variant(foo_v1) \ + match(construct={dispatch}, device={arch(ppc)}), \ + adjust_args(need_device_ptr:AAA) adjust_args(nothing:AAA) + +// expected-error@+2 {{use of undeclared identifier 'J'}} +#pragma omp declare variant(foo_v1) \ + adjust_args(nothing:J) \ + match(construct={dispatch}, device={arch(x86,x86_64)}) + +// expected-error@+2 {{expected reference to one of the parameters of function 'foo'}} +#pragma omp declare variant(foo_v3) \ + adjust_args(nothing:Other) \ + match(construct={dispatch}, device={arch(x86,x86_64)}) + +// expected-error@+2 {{'adjust_args' clause requires 'dispatch' context selector}} +#pragma omp declare variant(foo_v3) \ + adjust_args(nothing:BBB) match(construct={target}, device={arch(arm)}) + +// expected-error@+2 {{'adjust_args' clause requires 'dispatch' context selector}} +#pragma omp declare variant(foo_v3) \ + adjust_args(nothing:BBB) match(device={arch(ppc)}) +#endif // OMP51 +#ifdef OMP50 +// expected-error@+2 {{expected 'match' clause on 'omp declare variant' directive}} +#pragma omp declare variant(foo_v1) \ + adjust_args(need_device_ptr:AAA) match(device={arch(arm)}) +#endif // OMP50 + +void foo(float *AAA, float *BBB, int *I) { return; } + diff --git a/clang/test/OpenMP/declare_variant_messages.c b/clang/test/OpenMP/declare_variant_messages.c --- a/clang/test/OpenMP/declare_variant_messages.c +++ b/clang/test/OpenMP/declare_variant_messages.c @@ -20,12 +20,12 @@ #pragma omp declare variant(foo) match(xxx) // expected-warning {{'xxx' is not a valid context set in a `declare variant`; set ignored}} expected-note {{context set options are: 'construct' 'device' 'implementation' 'user'}} expected-note {{the ignored set spans until here}} #pragma omp declare variant(foo) match(xxx=) // expected-warning {{'xxx' is not a valid context set in a `declare variant`; set ignored}} expected-note {{context set options are: 'construct' 'device' 'implementation' 'user'}} expected-note {{the ignored set spans until here}} #pragma omp declare variant(foo) match(xxx=yyy) // expected-warning {{'xxx' is not a valid context set in a `declare variant`; set ignored}} expected-note {{context set options are: 'construct' 'device' 'implementation' 'user'}} expected-note {{the ignored set spans until here}} -#pragma omp declare variant(foo) match(xxx=yyy}) // expected-error {{expected ')'}} expected-warning {{'xxx' is not a valid context set in a `declare variant`; set ignored}} expected-note {{context set options are: 'construct' 'device' 'implementation' 'user'}} expected-note {{the ignored set spans until here}} expected-note {{to match this '('}} +#pragma omp declare variant(foo) match(xxx=yyy}) // expected-error {{expected ')'}} expected-warning {{'xxx' is not a valid context set in a `declare variant`; set ignored}} expected-note {{context set options are: 'construct' 'device' 'implementation' 'user'}} expected-note {{the ignored set spans until here}} expected-note {{to match this '('}} expected-error {{expected 'match' clause on 'omp declare variant' directive}} #pragma omp declare variant(foo) match(xxx={) // expected-error {{expected ')'}} expected-warning {{'xxx' is not a valid context set in a `declare variant`; set ignored}} expected-note {{context set options are: 'construct' 'device' 'implementation' 'user'}} expected-note {{the ignored set spans until here}} expected-note {{to match this '('}} #pragma omp declare variant(foo) match(xxx={}) // expected-warning {{'xxx' is not a valid context set in a `declare variant`; set ignored}} expected-note {{context set options are: 'construct' 'device' 'implementation' 'user'}} expected-note {{the ignored set spans until here}} #pragma omp declare variant(foo) match(xxx={vvv, vvv}) // expected-warning {{'xxx' is not a valid context set in a `declare variant`; set ignored}} expected-note {{context set options are: 'construct' 'device' 'implementation' 'user'}} expected-note {{the ignored set spans until here}} #pragma omp declare variant(foo) match(xxx={vvv} xxx) // expected-warning {{'xxx' is not a valid context set in a `declare variant`; set ignored}} expected-note {{context set options are: 'construct' 'device' 'implementation' 'user'}} expected-note {{the ignored set spans until here}} -#pragma omp declare variant(foo) match(xxx={vvv}) xxx // expected-warning {{'xxx' is not a valid context set in a `declare variant`; set ignored}} expected-note {{context set options are: 'construct' 'device' 'implementation' 'user'}} expected-note {{the ignored set spans until here}} +#pragma omp declare variant(foo) match(xxx={vvv}) xxx // expected-warning {{'xxx' is not a valid context set in a `declare variant`; set ignored}} expected-note {{context set options are: 'construct' 'device' 'implementation' 'user'}} expected-note {{the ignored set spans until here}} expected-error {{expected 'match' clause on 'omp declare variant' directive}} #pragma omp declare variant(foo) match(implementation={xxx}) // expected-warning {{'xxx' is not a valid context selector for the context set 'implementation'; selector ignored}} expected-note {{context selector options are: 'vendor' 'extension' 'unified_address' 'unified_shared_memory' 'reverse_offload' 'dynamic_allocators' 'atomic_default_mem_order'}} expected-note {{the ignored selector spans until here}} #pragma omp declare variant(foo) match(implementation={vendor}) // expected-warning {{the context selector 'vendor' in context set 'implementation' requires a context property defined in parentheses; selector ignored}} expected-note {{the ignored selector spans until here}} #pragma omp declare variant(foo) match(implementation={vendor(}) // expected-error {{expected ')'}} expected-warning {{expected identifier or string literal describing a context property; property skipped}} expected-note {{context property options are: 'amd' 'arm' 'bsc' 'cray' 'fujitsu' 'gnu' 'ibm' 'intel' 'llvm' 'pgi' 'ti' 'unknown'}} expected-note {{to match this '('}} @@ -58,9 +58,9 @@ int score_and_cond_non_const(); #pragma omp declare variant(foo) match(construct={teams,parallel,for,simd}) -#pragma omp declare variant(foo) match(construct={target teams}) // expected-error {{expected ')'}} expected-warning {{expected '}' after the context selectors for the context set "construct"; '}' assumed}} expected-note {{to match this '('}} -#pragma omp declare variant(foo) match(construct={parallel for}) // expected-error {{expected ')'}} expected-warning {{expected '}' after the context selectors for the context set "construct"; '}' assumed}} expected-note {{to match this '('}} -#pragma omp declare variant(foo) match(construct={for simd}) // expected-error {{expected ')'}} expected-warning {{expected '}' after the context selectors for the context set "construct"; '}' assumed}} expected-note {{to match this '('}} +#pragma omp declare variant(foo) match(construct={target teams}) // expected-error {{expected ')'}} expected-warning {{expected '}' after the context selectors for the context set "construct"; '}' assumed}} expected-note {{to match this '('}} expected-error {{expected 'match' clause on 'omp declare variant' directive}} +#pragma omp declare variant(foo) match(construct={parallel for}) // expected-error {{expected ')'}} expected-warning {{expected '}' after the context selectors for the context set "construct"; '}' assumed}} expected-note {{to match this '('}} expected-error {{expected 'match' clause on 'omp declare variant' directive}} +#pragma omp declare variant(foo) match(construct={for simd}) // expected-error {{expected ')'}} expected-warning {{expected '}' after the context selectors for the context set "construct"; '}' assumed}} expected-note {{to match this '('}} expected-error {{expected 'match' clause on 'omp declare variant' directive}} int construct(void); #pragma omp declare variant(foo) match(xxx={}) // expected-warning {{'xxx' is not a valid context set in a `declare variant`; set ignored}} expected-note {{context set options are: 'construct' 'device' 'implementation' 'user'}} expected-note {{the ignored set spans until here}} diff --git a/clang/test/OpenMP/declare_variant_messages.cpp b/clang/test/OpenMP/declare_variant_messages.cpp --- a/clang/test/OpenMP/declare_variant_messages.cpp +++ b/clang/test/OpenMP/declare_variant_messages.cpp @@ -28,7 +28,7 @@ #pragma omp declare variant(foofoo ) match(implementation = {}) // expected-warning {{expected identifier or string literal describing a context selector; selector skipped}} expected-note {{context selector options are: 'vendor' 'extension' 'unified_address' 'unified_shared_memory' 'reverse_offload' 'dynamic_allocators' 'atomic_default_mem_order'}} expected-note {{the ignored selector spans until here}} #pragma omp declare variant(foofoo ) match(implementation = {vvv, vvv}) // expected-warning {{'vvv' is not a valid context selector for the context set 'implementation'; selector ignored}} expected-warning {{'vvv' is not a valid context selector for the context set 'implementation'; selector ignored}} expected-note {{context selector options are: 'vendor' 'extension' 'unified_address' 'unified_shared_memory' 'reverse_offload' 'dynamic_allocators' 'atomic_default_mem_order'}} expected-note {{the ignored selector spans until here}} expected-note {{context selector options are: 'vendor' 'extension' 'unified_address' 'unified_shared_memory' 'reverse_offload' 'dynamic_allocators' 'atomic_default_mem_order'}} expected-note {{the ignored selector spans until here}} #pragma omp declare variant(foofoo ) match(implementation = {vvv} implementation) // expected-error {{expected ')'}} expected-warning {{'vvv' is not a valid context selector for the context set 'implementation'; selector ignored}} expected-note {{context selector options are: 'vendor' 'extension' 'unified_address' 'unified_shared_memory' 'reverse_offload' 'dynamic_allocators' 'atomic_default_mem_order'}} expected-note {{the ignored selector spans until here}} expected-note {{to match this '('}} -#pragma omp declare variant(foofoo ) match(implementation = {vvv}) implementation // expected-warning {{'vvv' is not a valid context selector for the context set 'implementation'; selector ignored}} expected-note {{context selector options are: 'vendor' 'extension' 'unified_address' 'unified_shared_memory' 'reverse_offload' 'dynamic_allocators' 'atomic_default_mem_order'}} expected-note {{the ignored selector spans until here}} +#pragma omp declare variant(foofoo ) match(implementation = {vvv}) implementation // expected-warning {{'vvv' is not a valid context selector for the context set 'implementation'; selector ignored}} expected-note {{context selector options are: 'vendor' 'extension' 'unified_address' 'unified_shared_memory' 'reverse_offload' 'dynamic_allocators' 'atomic_default_mem_order'}} expected-note {{the ignored selector spans until here}} expected-error {{expected 'match' clause on 'omp declare variant' directive}} #pragma omp declare variant(foofoo ) match(implementation={xxx}) // expected-warning {{'xxx' is not a valid context selector for the context set 'implementation'; selector ignored}} expected-note {{context selector options are: 'vendor' 'extension' 'unified_address' 'unified_shared_memory' 'reverse_offload' 'dynamic_allocators' 'atomic_default_mem_order'}} expected-note {{the ignored selector spans until here}} #pragma omp declare variant(foofoo ) match(implementation={vendor}) // expected-warning {{the context selector 'vendor' in context set 'implementation' requires a context property defined in parentheses; selector ignored}} expected-note {{the ignored selector spans until here}} #pragma omp declare variant(foofoo ) match(implementation={vendor(}) // expected-error {{expected ')'}} expected-warning {{expected identifier or string literal describing a context property; property skipped}} expected-note {{context property options are: 'amd' 'arm' 'bsc' 'cray' 'fujitsu' 'gnu' 'ibm' 'intel' 'llvm' 'pgi' 'ti' 'unknown'}} expected-note {{to match this '('}} @@ -72,7 +72,7 @@ #pragma omp declare variant(foofoo ) match(user = {condition()}) // expected-error {{expected expression}} expected-error {{use of undeclared identifier 'expr'}} expected-error {{expected expression}} expected-note {{the ignored selector spans until here}} #pragma omp declare variant(foofoo ) match(user = {condition()}) // expected-error {{expected expression}} expected-error {{use of undeclared identifier 'expr'}} expected-error {{expected expression}} expected-note {{the ignored selector spans until here}} #pragma omp declare variant(foofoo ) match(implementation = {vvv} implementation) // expected-error {{expected ')'}} expected-warning {{'vvv' is not a valid context selector for the context set 'implementation'; selector ignored}} expected-note {{context selector options are: 'vendor' 'extension' 'unified_address' 'unified_shared_memory' 'reverse_offload' 'dynamic_allocators' 'atomic_default_mem_order'}} expected-note {{the ignored selector spans until here}} expected-note {{to match this '('}} -#pragma omp declare variant(foofoo ) match(implementation = {vvv}) xxx // expected-warning {{'vvv' is not a valid context selector for the context set 'implementation'; selector ignored}} expected-note {{context selector options are: 'vendor' 'extension' 'unified_address' 'unified_shared_memory' 'reverse_offload' 'dynamic_allocators' 'atomic_default_mem_order'}} expected-note {{the ignored selector spans until here}} +#pragma omp declare variant(foofoo ) match(implementation = {vvv}) xxx // expected-warning {{'vvv' is not a valid context selector for the context set 'implementation'; selector ignored}} expected-note {{context selector options are: 'vendor' 'extension' 'unified_address' 'unified_shared_memory' 'reverse_offload' 'dynamic_allocators' 'atomic_default_mem_order'}} expected-note {{the ignored selector spans until here}} expected-error {{expected 'match' clause on 'omp declare variant' directive}} #pragma omp declare variant(foofoo ) match(implementation={vendor(score ibm)}) // expected-error {{expected '(' after 'score'}} expected-warning {{expected '':'' after the score expression; '':'' assumed}} #pragma omp declare variant(foofoo ) match(implementation={vendor(score( ibm)}) // expected-error {{use of undeclared identifier 'ibm'}} expected-error {{expected ')'}} expected-warning {{expected '':'' after the score expression; '':'' assumed}} expected-warning {{expected identifier or string literal describing a context property; property skipped}} expected-note {{context property options are: 'amd' 'arm' 'bsc' 'cray' 'fujitsu' 'gnu' 'ibm' 'intel' 'llvm' 'pgi' 'ti' 'unknown'}} expected-note {{to match this '('}} #pragma omp declare variant(foofoo ) match(implementation={vendor(score(C ibm)}) // expected-error {{expected ')'}} expected-error {{expected ')'}} expected-warning {{expected '':'' after the score expression; '':'' assumed}} expected-warning {{expected identifier or string literal describing a context property; property skipped}} expected-note {{to match this '('}} expected-note {{context property options are: 'amd' 'arm' 'bsc' 'cray' 'fujitsu' 'gnu' 'ibm' 'intel' 'llvm' 'pgi' 'ti' 'unknown'}} expected-note {{to match this '('}} diff --git a/flang/lib/Semantics/check-omp-structure.cpp b/flang/lib/Semantics/check-omp-structure.cpp --- a/flang/lib/Semantics/check-omp-structure.cpp +++ b/flang/lib/Semantics/check-omp-structure.cpp @@ -1422,6 +1422,7 @@ CHECK_SIMPLE_CLAUSE(Nocontext, OMPC_nocontext) CHECK_SIMPLE_CLAUSE(Filter, OMPC_filter) CHECK_SIMPLE_CLAUSE(When, OMPC_when) +CHECK_SIMPLE_CLAUSE(AdjustArgs, OMPC_adjust_args) CHECK_REQ_SCALAR_INT_CLAUSE(Grainsize, OMPC_grainsize) CHECK_REQ_SCALAR_INT_CLAUSE(NumTasks, OMPC_num_tasks) diff --git a/llvm/include/llvm/Frontend/OpenMP/OMP.td b/llvm/include/llvm/Frontend/OpenMP/OMP.td --- a/llvm/include/llvm/Frontend/OpenMP/OMP.td +++ b/llvm/include/llvm/Frontend/OpenMP/OMP.td @@ -314,6 +314,7 @@ } def OMPC_DeviceType : Clause<"device_type"> {} def OMPC_Match : Clause<"match"> {} +def OMPC_AdjustArgs : Clause<"adjust_args"> { } def OMPC_Depobj : Clause<"depobj"> { let clangClass = "OMPDepobjClause"; let isImplicit = true; @@ -1518,6 +1519,9 @@ let allowedClauses = [ VersionedClause ]; + let allowedExclusiveClauses = [ + VersionedClause + ]; } def OMP_MasterTaskloop : Directive<"master taskloop"> { let allowedClauses = [