Index: clang/include/clang/Basic/Attr.td =================================================================== --- clang/include/clang/Basic/Attr.td +++ clang/include/clang/Basic/Attr.td @@ -3631,6 +3631,8 @@ let Args = [ ExprArgument<"VariantFuncRef">, OMPTraitInfoArgument<"TraitInfos">, + VariadicExprArgument<"AdjustArgsNothing">, + VariadicExprArgument<"AdjustArgsNeedDevicePtr"> ]; let AdditionalMembers = [{ OMPTraitInfo &getTraitInfo() { return *traitInfos; } Index: clang/include/clang/Basic/DiagnosticParseKinds.td =================================================================== --- clang/include/clang/Basic/DiagnosticParseKinds.td +++ clang/include/clang/Basic/DiagnosticParseKinds.td @@ -1323,7 +1323,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">; Index: clang/include/clang/Basic/DiagnosticSemaKinds.td =================================================================== --- clang/include/clang/Basic/DiagnosticSemaKinds.td +++ clang/include/clang/Basic/DiagnosticSemaKinds.td @@ -10619,6 +10619,10 @@ def err_omp_dispatch_statement_call : Error<"statement after '#pragma omp dispatch' must be a direct call" " to a target function or an assignment to one">; +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 { Index: clang/include/clang/Basic/OpenMPKinds.h =================================================================== --- clang/include/clang/Basic/OpenMPKinds.h +++ clang/include/clang/Basic/OpenMPKinds.h @@ -166,6 +166,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, unsigned OpenMPVersion); const char *getOpenMPSimpleClauseTypeName(OpenMPClauseKind Kind, unsigned Type); Index: clang/include/clang/Basic/OpenMPKinds.def =================================================================== --- clang/include/clang/Basic/OpenMPKinds.def +++ 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) @@ -147,6 +150,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 Index: clang/include/clang/Parse/Parser.h =================================================================== --- clang/include/clang/Parse/Parser.h +++ clang/include/clang/Parse/Parser.h @@ -3165,6 +3165,14 @@ /// Parses OpenMP context selectors. bool parseOMPContextSelectors(SourceLocation Loc, OMPTraitInfo &TI); + /// Parse a `match` or 'adjust_args' clause for an + /// '#pragma omp declare variant'. Return true if there was an error. + bool + parseOMPDeclareVariantAnyClause(SourceLocation Loc, OMPTraitInfo &TI, + OMPTraitInfo *ParentTI, + SmallVectorImpl &AdjustNothing, + SmallVectorImpl &AdjustNeedDevicePtr); + /// Parse a `match` clause for an '#pragma omp declare variant'. Return true /// if there was an error. bool parseOMPDeclareVariantMatchClause(SourceLocation Loc, OMPTraitInfo &TI, Index: clang/include/clang/Sema/Sema.h =================================================================== --- clang/include/clang/Sema/Sema.h +++ clang/include/clang/Sema/Sema.h @@ -10839,8 +10839,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, + MutableArrayRef AdjustArgsNothing, + MutableArrayRef AdjustArgsNeedDevicePtr, SourceRange SR); OMPClause *ActOnOpenMPSingleExprClause(OpenMPClauseKind Kind, Expr *Expr, Index: clang/lib/AST/AttrImpl.cpp =================================================================== --- clang/lib/AST/AttrImpl.cpp +++ clang/lib/AST/AttrImpl.cpp @@ -208,6 +208,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" Index: clang/lib/Basic/OpenMPKinds.cpp =================================================================== --- clang/lib/Basic/OpenMPKinds.cpp +++ clang/lib/Basic/OpenMPKinds.cpp @@ -123,6 +123,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: @@ -366,6 +371,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: Index: clang/lib/Parse/ParseOpenMP.cpp =================================================================== --- clang/lib/Parse/ParseOpenMP.cpp +++ clang/lib/Parse/ParseOpenMP.cpp @@ -1401,8 +1401,16 @@ OMPTraitInfo *ParentTI = Actions.getOMPTraitInfoForSurroundingScope(); ASTContext &ASTCtx = Actions.getASTContext(); OMPTraitInfo &TI = ASTCtx.getNewOMPTraitInfo(); - if (parseOMPDeclareVariantMatchClause(Loc, TI, ParentTI)) - return; + SmallVector AdjustNothing; + SmallVector AdjustNeedDevicePtr; + do { + if (parseOMPDeclareVariantAnyClause(Loc, TI, ParentTI, AdjustNothing, + AdjustNeedDevicePtr)) + return; + // Skip ',' if any. + if (Tok.is(tok::comma)) + ConsumeToken(); + } while (Tok.isNot(tok::annot_pragma_openmp_end)); Optional> DeclVarData = Actions.checkOpenMPDeclareVariantFunction( @@ -1414,13 +1422,51 @@ 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(); } +bool Parser::parseOMPDeclareVariantAnyClause( + SourceLocation Loc, OMPTraitInfo &TI, OMPTraitInfo *ParentTI, + SmallVectorImpl &AdjustNothing, + SmallVectorImpl &AdjustNeedDevicePtr) { + OpenMPClauseKind CKind = Tok.isAnnotation() + ? OMPC_unknown + : getOpenMPClauseKind(PP.getSpelling(Tok)); + if (CKind == OMPC_adjust_args && + isAllowedClauseForDirective(OMPD_declare_variant, CKind, + getLangOpts().OpenMP)) { + bool IsError = false; + ConsumeToken(); + Parser::OpenMPVarListDataTy Data; + SmallVector Vars; + + if (ParseOpenMPVarList(OMPD_declare_variant, OMPC_adjust_args, Vars, Data)) + IsError = true; + + if (!IsError) { + if (Data.ExtraModifier == OMPC_ADJUST_ARGS_nothing) + llvm::append_range(AdjustNothing, Vars); + else + llvm::append_range(AdjustNeedDevicePtr, Vars); + } + return false; + } + if (CKind != OMPC_match) { + Diag(Tok.getLocation(), diag::err_omp_declare_variant_wrong_clause) + << (getLangOpts().OpenMP < 51 ? 0 : 1); + while (!SkipUntil(tok::annot_pragma_openmp_end, Parser::StopBeforeMatch)) + ; + // Skip the last annot_pragma_openmp_end. + (void)ConsumeAnnotationToken(); + return true; + } + return parseOMPDeclareVariantMatchClause(Loc, TI, ParentTI); +} + bool Parser::parseOMPDeclareVariantMatchClause(SourceLocation Loc, OMPTraitInfo &TI, OMPTraitInfo *ParentTI) { @@ -1430,7 +1476,7 @@ : getOpenMPClauseKind(PP.getSpelling(Tok)); if (CKind != OMPC_match) { Diag(Tok.getLocation(), diag::err_omp_declare_variant_wrong_clause) - << getOpenMPClauseName(OMPC_match); + << (getLangOpts().OpenMP < 51 ? 0 : 1); while (!SkipUntil(tok::annot_pragma_openmp_end, Parser::StopBeforeMatch)) ; // Skip the last annot_pragma_openmp_end. @@ -3927,6 +3973,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().OpenMP); + 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 = ConsumeToken(); + else + Diag(Tok, diag::warn_pragma_expected_colon) << "adjust-op"; + } } bool IsComma = @@ -3934,7 +3997,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))) { Index: clang/lib/Sema/SemaOpenMP.cpp =================================================================== --- clang/lib/Sema/SemaOpenMP.cpp +++ clang/lib/Sema/SemaOpenMP.cpp @@ -6693,7 +6693,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); } @@ -7066,12 +7068,70 @@ 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, + MutableArrayRef AdjustArgsNothing, + MutableArrayRef 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; + bool Found = false; + TI.getAsVariantMatchInfo(Context, VMI); + for (TraitProperty Property : VMI.ConstructTraits) + if (Property == llvm::omp::TraitProperty::construct_dispatch_dispatch) { + Found = true; + break; + } + if (!Found) { + 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->getDeclName() << 0; + return; + } + + auto *NewAttr = OMPDeclareVariantAttr::CreateImplicit( + Context, VariantRef, &TI, AdjustArgsNothing.data(), + AdjustArgsNothing.size(), AdjustArgsNeedDevicePtr.data(), + AdjustArgsNeedDevicePtr.size(), SR); FD->addAttr(NewAttr); } Index: clang/lib/Sema/SemaTemplateInstantiateDecl.cpp =================================================================== --- clang/lib/Sema/SemaTemplateInstantiateDecl.cpp +++ clang/lib/Sema/SemaTemplateInstantiateDecl.cpp @@ -479,7 +479,26 @@ } } - S.ActOnOpenMPDeclareVariantDirective(FD, E, TI, Attr.getRange()); + SmallVector NothingExprs; + SmallVector NeedDevicePtrExprs; + if (Attr.adjustArgsNothing_size()) { + for (Expr *E : Attr.adjustArgsNothing()) { + ExprResult ER = Subst(E); + if (ER.isInvalid()) + continue; + NothingExprs.push_back(ER.get()); + } + } + if (Attr.adjustArgsNeedDevicePtr_size()) { + 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( Index: clang/test/OpenMP/declare_variant_clauses_ast_print.cpp =================================================================== --- /dev/null +++ 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 Index: clang/test/OpenMP/declare_variant_clauses_messages.cpp =================================================================== --- /dev/null +++ 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; } + Index: clang/test/OpenMP/declare_variant_messages.c =================================================================== --- clang/test/OpenMP/declare_variant_messages.c +++ 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 '('}} Index: clang/test/OpenMP/declare_variant_messages.cpp =================================================================== --- clang/test/OpenMP/declare_variant_messages.cpp +++ 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 '('}} Index: flang/lib/Semantics/check-omp-structure.cpp =================================================================== --- flang/lib/Semantics/check-omp-structure.cpp +++ flang/lib/Semantics/check-omp-structure.cpp @@ -731,6 +731,7 @@ CHECK_SIMPLE_CLAUSE(Use, OMPC_use) CHECK_SIMPLE_CLAUSE(Novariants, OMPC_novariants) CHECK_SIMPLE_CLAUSE(Nocontext, OMPC_nocontext) +CHECK_SIMPLE_CLAUSE(AdjustArgs, OMPC_adjust_args) CHECK_REQ_SCALAR_INT_CLAUSE(Allocator, OMPC_allocator) CHECK_REQ_SCALAR_INT_CLAUSE(Grainsize, OMPC_grainsize) Index: llvm/include/llvm/Frontend/OpenMP/OMP.td =================================================================== --- llvm/include/llvm/Frontend/OpenMP/OMP.td +++ llvm/include/llvm/Frontend/OpenMP/OMP.td @@ -310,6 +310,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; @@ -1494,6 +1495,9 @@ let allowedClauses = [ VersionedClause ]; + let allowedExclusiveClauses = [ + VersionedClause + ]; } def OMP_MasterTaskloop : Directive<"master taskloop"> { let allowedClauses = [