Index: clang/include/clang/Basic/Attr.td =================================================================== --- clang/include/clang/Basic/Attr.td +++ clang/include/clang/Basic/Attr.td @@ -3691,7 +3691,10 @@ ExprArgument<"VariantFuncRef">, OMPTraitInfoArgument<"TraitInfos">, VariadicExprArgument<"AdjustArgsNothing">, - VariadicExprArgument<"AdjustArgsNeedDevicePtr"> + VariadicExprArgument<"AdjustArgsNeedDevicePtr">, + VariadicEnumArgument<"AppendArgs", "InteropType", + ["target", "targetsync", "target,targetsync"], + ["Target", "TargetSync", "Target_TargetSync"]> ]; 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 @@ -1356,9 +1356,11 @@ "illegal OpenMP user-defined mapper identifier">; def err_omp_mapper_expected_declarator : Error< "expected declarator on 'omp declare mapper' directive">; +def err_omp_unexpected_append_op : Error< + "unexpected append-op in 'append_args' clause, expected 'interop'">; def err_omp_declare_variant_wrong_clause : Error< - "expected %select{'match'|'match' or 'adjust_args'}0 clause on " - "'omp declare variant' directive">; + "expected %select{'match'|'match', 'adjust_args', or 'append_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 @@ -10751,8 +10751,8 @@ "|return type|constexpr specification|inline specification|storage class|" "linkage}0">; def err_omp_declare_variant_incompat_types : Error< - "variant in '#pragma omp declare variant' with type %0 is incompatible with type %1" - >; + "variant in '#pragma omp declare variant' with type %0 is incompatible with" + " type %1%select{| with appended arguments}2">; def warn_omp_declare_variant_marked_as_declare_variant : Warning< "variant function in '#pragma omp declare variant' is itself marked as '#pragma omp declare variant'" >, InGroup; Index: clang/include/clang/Parse/Parser.h =================================================================== --- clang/include/clang/Parse/Parser.h +++ clang/include/clang/Parse/Parser.h @@ -3205,6 +3205,10 @@ /// Parses OpenMP context selectors. bool parseOMPContextSelectors(SourceLocation Loc, OMPTraitInfo &TI); + /// Parse an 'append_args' clause for '#pragma omp declare variant'. + bool ParseOpenMPAppendArgs( + SmallVectorImpl &InterOpTypes); + /// 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 @@ -10964,11 +10964,14 @@ /// \param VariantRef Expression that references the variant function, which /// must be used instead of the original one, specified in \p DG. /// \param TI The trait info object representing the match clause. + /// \param NumAppendArgs The number of omp_interop_t arguments to account for + /// in checking. /// \returns None, if the function/variant function are not compatible with /// the pragma, pair of original function/variant ref expression otherwise. Optional> checkOpenMPDeclareVariantFunction(DeclGroupPtrTy DG, Expr *VariantRef, - OMPTraitInfo &TI, SourceRange SR); + OMPTraitInfo &TI, unsigned NumAppendArgs, + SourceRange SR); /// Called on well-formed '\#pragma omp declare variant' after parsing of /// the associated method/function. @@ -10977,10 +10980,19 @@ /// \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. + /// \param AdjustArgsNothing The list of 'nothing' arguments. + /// \param AdjustArgsNeedDevicePtr The list of 'need_device_ptr' arguments. + /// \param AppendArgs The list of 'append_args' arguments. + /// \param AdjustArgsLoc The Location of an 'adjust_args' clause. + /// \param AppendArgsLoc The Location of an 'append_args' clause. + /// \param SR The SourceRange of the 'declare variant' directive. void ActOnOpenMPDeclareVariantDirective( FunctionDecl *FD, Expr *VariantRef, OMPTraitInfo &TI, ArrayRef AdjustArgsNothing, - ArrayRef AdjustArgsNeedDevicePtr, SourceRange SR); + ArrayRef AdjustArgsNeedDevicePtr, + ArrayRef AppendArgs, + SourceLocation AdjustArgsLoc, SourceLocation AppendArgsLoc, + SourceRange SR); OMPClause *ActOnOpenMPSingleExprClause(OpenMPClauseKind Kind, Expr *Expr, Index: clang/lib/AST/AttrImpl.cpp =================================================================== --- clang/lib/AST/AttrImpl.cpp +++ clang/lib/AST/AttrImpl.cpp @@ -214,6 +214,21 @@ PrintExprs(adjustArgsNeedDevicePtr_begin(), adjustArgsNeedDevicePtr_end()); OS << ")"; } + + auto PrintInteropTypes = [&OS](InteropType *Begin, InteropType *End) { + for (InteropType *I = Begin; I != End; ++I) { + if (I != Begin) + OS << ", "; + OS << "interop("; + OS << ConvertInteropTypeToStr(*I); + OS << ")"; + } + }; + if (appendArgs_size()) { + OS << " append_args("; + PrintInteropTypes(appendArgs_begin(), appendArgs_end()); + OS << ")"; + } } #include "clang/AST/AttrImpl.inc" Index: clang/lib/Basic/OpenMPKinds.cpp =================================================================== --- clang/lib/Basic/OpenMPKinds.cpp +++ clang/lib/Basic/OpenMPKinds.cpp @@ -191,6 +191,7 @@ case OMPC_uses_allocators: case OMPC_affinity: case OMPC_when: + case OMPC_append_args: break; default: break; @@ -445,6 +446,7 @@ case OMPC_uses_allocators: case OMPC_affinity: case OMPC_when: + case OMPC_append_args: break; default: break; Index: clang/lib/CodeGen/CGStmtOpenMP.cpp =================================================================== --- clang/lib/CodeGen/CGStmtOpenMP.cpp +++ clang/lib/CodeGen/CGStmtOpenMP.cpp @@ -5990,6 +5990,7 @@ case OMPC_filter: case OMPC_when: case OMPC_adjust_args: + case OMPC_append_args: llvm_unreachable("Clause is not allowed in 'omp atomic'."); } } Index: clang/lib/Parse/ParseOpenMP.cpp =================================================================== --- clang/lib/Parse/ParseOpenMP.cpp +++ clang/lib/Parse/ParseOpenMP.cpp @@ -1404,6 +1404,8 @@ OMPTraitInfo &TI = ASTCtx.getNewOMPTraitInfo(); SmallVector AdjustNothing; SmallVector AdjustNeedDevicePtr; + SmallVector AppendArgs; + SourceLocation AdjustArgsLoc, AppendArgsLoc; // At least one clause is required. if (Tok.is(tok::annot_pragma_openmp_end)) { @@ -1428,6 +1430,7 @@ IsError = parseOMPDeclareVariantMatchClause(Loc, TI, ParentTI); break; case OMPC_adjust_args: { + AdjustArgsLoc = Tok.getLocation(); ConsumeToken(); Parser::OpenMPVarListDataTy Data; SmallVector Vars; @@ -1440,6 +1443,19 @@ Vars); break; } + case OMPC_append_args: + if (!AppendArgs.empty()) { + Diag(AppendArgsLoc, diag::err_omp_more_one_clause) + << getOpenMPDirectiveName(OMPD_declare_variant) + << getOpenMPClauseName(CKind) << 0; + IsError = true; + } + if (!IsError) { + AppendArgsLoc = Tok.getLocation(); + ConsumeToken(); + IsError = ParseOpenMPAppendArgs(AppendArgs); + } + break; default: llvm_unreachable("Unexpected clause for declare variant."); } @@ -1458,18 +1474,109 @@ Optional> DeclVarData = Actions.checkOpenMPDeclareVariantFunction( - Ptr, AssociatedFunction.get(), TI, + Ptr, AssociatedFunction.get(), TI, AppendArgs.size(), SourceRange(Loc, Tok.getLocation())); if (DeclVarData && !TI.Sets.empty()) Actions.ActOnOpenMPDeclareVariantDirective( DeclVarData->first, DeclVarData->second, TI, AdjustNothing, - AdjustNeedDevicePtr, SourceRange(Loc, Tok.getLocation())); + AdjustNeedDevicePtr, AppendArgs, AdjustArgsLoc, AppendArgsLoc, + SourceRange(Loc, Tok.getLocation())); // Skip the last annot_pragma_openmp_end. (void)ConsumeAnnotationToken(); } +/// Parse a list of interop-types. These are 'target' and 'targetsync'. Both +/// are allowed but duplication of either is not meaningful. Return the +/// value pair when a valid list is specified. +static llvm::Optional> parseInteropTypeList(Parser &P) { + const Token &Tok = P.getCurToken(); + Preprocessor &PP = P.getPreprocessor(); + bool HasError = false; + bool IsTarget = false; + bool IsTargetSync = false; + + while (Tok.is(tok::identifier)) { + if (PP.getSpelling(Tok) == "target") { + // OpenMP 5.1 [2.15.1, interop Construct, Restrictions] + // Each interop-type may be specified on an action-clause at most + // once. + if (IsTarget) + P.Diag(Tok, diag::warn_omp_more_one_interop_type) << "target"; + IsTarget = true; + } else if (PP.getSpelling(Tok) == "targetsync") { + if (IsTargetSync) + P.Diag(Tok, diag::warn_omp_more_one_interop_type) << "targetsync"; + IsTargetSync = true; + } else { + HasError = true; + P.Diag(Tok, diag::err_omp_expected_interop_type); + } + P.ConsumeToken(); + + if (!Tok.is(tok::comma)) + break; + P.ConsumeToken(); + } + if (HasError) + return None; + + if (!IsTarget && !IsTargetSync) { + P.Diag(Tok, diag::err_omp_expected_interop_type); + return None; + } + + return std::make_pair(IsTarget, IsTargetSync); +} + +bool Parser::ParseOpenMPAppendArgs( + SmallVectorImpl &InterOpTypes) { + bool HasError = false; + // Parse '('. + BalancedDelimiterTracker T(*this, tok::l_paren, tok::annot_pragma_openmp_end); + if (T.expectAndConsume(diag::err_expected_lparen_after, + getOpenMPClauseName(OMPC_append_args).data())) + return true; + + // Parse the list of append-ops, each is; + // interop(interop-type[,interop-type]...) + while (Tok.is(tok::identifier) && PP.getSpelling(Tok) == "interop") { + ConsumeToken(); + BalancedDelimiterTracker IT(*this, tok::l_paren, + tok::annot_pragma_openmp_end); + if (IT.expectAndConsume(diag::err_expected_lparen_after, "interop")) + return true; + + // Parse the interop-types. + if (Optional> InteropTypes = + parseInteropTypeList(*this)) { + bool IsTarget = InteropTypes->first; + bool IsTargetSync = InteropTypes->second; + if (IsTarget && IsTargetSync) + InterOpTypes.push_back( + OMPDeclareVariantAttr::InteropType::Target_TargetSync); + else if (IsTarget) + InterOpTypes.push_back(OMPDeclareVariantAttr::InteropType::Target); + else if (IsTargetSync) + InterOpTypes.push_back(OMPDeclareVariantAttr::InteropType::TargetSync); + } else { + HasError = true; + } + IT.consumeClose(); + if (Tok.is(tok::comma)) + ConsumeToken(); + } + if (!HasError && InterOpTypes.empty()) { + HasError = true; + Diag(Tok.getLocation(), diag::err_omp_unexpected_append_op); + SkipUntil(tok::comma, tok::r_paren, tok::annot_pragma_openmp_end, + StopBeforeMatch); + } + HasError = T.consumeClose() || HasError; + return HasError; +} + bool Parser::parseOMPDeclareVariantMatchClause(SourceLocation Loc, OMPTraitInfo &TI, OMPTraitInfo *ParentTI) { @@ -3342,36 +3449,15 @@ } // Parse the interop-types. - bool HasError = false; - while (Tok.is(tok::identifier)) { - if (PP.getSpelling(Tok) == "target") { - // OpenMP 5.1 [2.15.1, interop Construct, Restrictions] - // Each interop-type may be specified on an action-clause at most - // once. - if (IsTarget) - Diag(Tok, diag::warn_omp_more_one_interop_type) << "target"; - IsTarget = true; - } else if (PP.getSpelling(Tok) == "targetsync") { - if (IsTargetSync) - Diag(Tok, diag::warn_omp_more_one_interop_type) << "targetsync"; - IsTargetSync = true; - } else { - HasError = true; - Diag(Tok, diag::err_omp_expected_interop_type); - } - ConsumeToken(); - - if (!Tok.is(tok::comma)) - break; - ConsumeToken(); + if (Optional> InteropTypes = + parseInteropTypeList(*this)) { + IsTarget = InteropTypes->first; + IsTargetSync = InteropTypes->second; + if (Tok.isNot(tok::colon)) + Diag(Tok, diag::warn_pragma_expected_colon) << "interop types"; } - if (!HasError && !IsTarget && !IsTargetSync) - Diag(Tok, diag::err_omp_expected_interop_type); - if (Tok.is(tok::colon)) ConsumeToken(); - else if (IsTarget || IsTargetSync) - Diag(Tok, diag::warn_pragma_expected_colon) << "interop types"; } // Parse the variable. Index: clang/lib/Sema/SemaOpenMP.cpp =================================================================== --- clang/lib/Sema/SemaOpenMP.cpp +++ clang/lib/Sema/SemaOpenMP.cpp @@ -6810,7 +6810,8 @@ auto *OMPDeclareVariantA = OMPDeclareVariantAttr::CreateImplicit( Context, VariantFuncRef, DVScope.TI, /*NothingArgs=*/nullptr, /*NothingArgsSize=*/0, - /*NeedDevicePtrArgs=*/nullptr, /*NeedDevicePtrArgsSize=*/0); + /*NeedDevicePtrArgs=*/nullptr, /*NeedDevicePtrArgsSize=*/0, + /*AppendArgs=*/nullptr, /*AppendArgsSize=*/0); for (FunctionDecl *BaseFD : Bases) BaseFD->addAttr(OMPDeclareVariantA); } @@ -6924,6 +6925,7 @@ Optional> Sema::checkOpenMPDeclareVariantFunction(Sema::DeclGroupPtrTy DG, Expr *VariantRef, OMPTraitInfo &TI, + unsigned NumAppendArgs, SourceRange SR) { if (!DG || DG.get().isNull()) return None; @@ -7011,6 +7013,40 @@ if (TI.anyScoreOrCondition(HandleNonConstantScoresAndConditions)) return None; + auto AdjustFunctionTypeForAppendArgs = [&](QualType FT, unsigned NumArgs) { + if (NumArgs == 0) + return FT; + auto *PTy = dyn_cast(FT); + auto *FTy = dyn_cast(FT); + if (!PTy && FTy) { + FunctionType::ExtInfo Ext = FTy->getExtInfo(); + FunctionProtoType::ExtProtoInfo EPI; + EPI.ExtInfo = Ext; + QualType RetTy = Context.VoidTy; + PTy = dyn_cast( + Context.getFunctionType(RetTy, None, EPI)); + } + llvm::SmallVector Params; + Params.append(PTy->param_type_begin(), PTy->param_type_end()); + + // Add omp_interop_t for each append_arg. + QualType InteropType = Context.VoidPtrTy; + LookupResult Result(*this, &Context.Idents.get("omp_interop_t"), + SR.getBegin(), Sema::LookupOrdinaryName); + if (LookupName(Result, getCurScope())) { + NamedDecl *ND = Result.getFoundDecl(); + if (const auto *TD = dyn_cast(ND)) + InteropType = QualType(TD->getTypeForDecl(), 0); + } + Params.insert(Params.end(), NumArgs, InteropType); + + QualType NewFnTy = Context.getFunctionType(PTy->getReturnType(), Params, + PTy->getExtProtoInfo()); + return NewFnTy; + }; + QualType AdjustedFnType = + AdjustFunctionTypeForAppendArgs(FD->getType(), NumAppendArgs); + // Convert VariantRef expression to the type of the original function to // resolve possible conflicts. ExprResult VariantRefCast = VariantRef; @@ -7020,7 +7056,7 @@ if (Method && !Method->isStatic()) { const Type *ClassType = Context.getTypeDeclType(Method->getParent()).getTypePtr(); - FnPtrType = Context.getMemberPointerType(FD->getType(), ClassType); + FnPtrType = Context.getMemberPointerType(AdjustedFnType, ClassType); ExprResult ER; { // Build adrr_of unary op to correctly handle type checks for member @@ -7036,7 +7072,7 @@ } VariantRef = ER.get(); } else { - FnPtrType = Context.getPointerType(FD->getType()); + FnPtrType = Context.getPointerType(AdjustedFnType); } QualType VarianPtrType = Context.getPointerType(VariantRef->getType()); if (VarianPtrType.getUnqualifiedType() != FnPtrType.getUnqualifiedType()) { @@ -7051,7 +7087,7 @@ diag::err_omp_declare_variant_incompat_types) << VariantRef->getType() << ((Method && !Method->isStatic()) ? FnPtrType : FD->getType()) - << VariantRef->getSourceRange(); + << (NumAppendArgs ? 1 : 0) << VariantRef->getSourceRange(); return None; } VariantRefCast = PerformImplicitConversion( @@ -7093,11 +7129,12 @@ // Check if function types are compatible in C. if (!LangOpts.CPlusPlus) { QualType NewType = - Context.mergeFunctionTypes(FD->getType(), NewFD->getType()); + Context.mergeFunctionTypes(AdjustedFnType, NewFD->getType()); if (NewType.isNull()) { Diag(VariantRef->getExprLoc(), diag::err_omp_declare_variant_incompat_types) - << NewFD->getType() << FD->getType() << VariantRef->getSourceRange(); + << NewFD->getType() << FD->getType() << (NumAppendArgs ? 1 : 0) + << VariantRef->getSourceRange(); return None; } if (NewType->isFunctionProtoType()) { @@ -7186,7 +7223,10 @@ void Sema::ActOnOpenMPDeclareVariantDirective( FunctionDecl *FD, Expr *VariantRef, OMPTraitInfo &TI, ArrayRef AdjustArgsNothing, - ArrayRef AdjustArgsNeedDevicePtr, SourceRange SR) { + ArrayRef AdjustArgsNeedDevicePtr, + ArrayRef AppendArgs, + SourceLocation AdjustArgsLoc, SourceLocation AppendArgsLoc, + 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 @@ -7197,15 +7237,18 @@ llvm::append_range(AllAdjustArgs, AdjustArgsNothing); llvm::append_range(AllAdjustArgs, AdjustArgsNeedDevicePtr); - if (!AllAdjustArgs.empty()) { + if (!AllAdjustArgs.empty() || !AppendArgs.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); + if (!AllAdjustArgs.empty()) + Diag(AdjustArgsLoc, diag::err_omp_clause_requires_dispatch_construct) + << getOpenMPClauseName(OMPC_adjust_args); + if (!AppendArgs.empty()) + Diag(AppendArgsLoc, diag::err_omp_clause_requires_dispatch_construct) + << getOpenMPClauseName(OMPC_append_args); return; } } @@ -7242,7 +7285,9 @@ Context, VariantRef, &TI, const_cast(AdjustArgsNothing.data()), AdjustArgsNothing.size(), const_cast(AdjustArgsNeedDevicePtr.data()), - AdjustArgsNeedDevicePtr.size(), SR); + AdjustArgsNeedDevicePtr.size(), + const_cast(AppendArgs.data()), + AppendArgs.size(), SR); FD->addAttr(NewAttr); } Index: clang/lib/Sema/SemaTemplateInstantiateDecl.cpp =================================================================== --- clang/lib/Sema/SemaTemplateInstantiateDecl.cpp +++ clang/lib/Sema/SemaTemplateInstantiateDecl.cpp @@ -441,6 +441,7 @@ // begin declare variant` (which use implicit attributes). Optional> DeclVarData = S.checkOpenMPDeclareVariantFunction(S.ConvertDeclToDeclGroup(New), E, TI, + Attr.appendArgs_size(), Attr.getRange()); if (!DeclVarData) @@ -483,6 +484,8 @@ SmallVector NothingExprs; SmallVector NeedDevicePtrExprs; + SmallVector AppendArgs; + for (Expr *E : Attr.adjustArgsNothing()) { ExprResult ER = Subst(E); if (ER.isInvalid()) @@ -495,8 +498,12 @@ continue; NeedDevicePtrExprs.push_back(ER.get()); } - S.ActOnOpenMPDeclareVariantDirective(FD, E, TI, NothingExprs, - NeedDevicePtrExprs, Attr.getRange()); + for (auto A : Attr.appendArgs()) + AppendArgs.push_back(A); + + S.ActOnOpenMPDeclareVariantDirective( + FD, E, TI, NothingExprs, NeedDevicePtrExprs, AppendArgs, SourceLocation(), + SourceLocation(), Attr.getRange()); } static void instantiateDependentAMDGPUFlatWorkGroupSizeAttr( Index: clang/test/OpenMP/declare_variant_clauses_ast_print.cpp =================================================================== --- clang/test/OpenMP/declare_variant_clauses_ast_print.cpp +++ clang/test/OpenMP/declare_variant_clauses_ast_print.cpp @@ -104,4 +104,48 @@ Foo(A, B); } +typedef void *omp_interop_t; + +void bar_v1(float* F1, float *F2, omp_interop_t); +void bar_v2(float* F1, float *F2, omp_interop_t, omp_interop_t); + +//PRINT: #pragma omp declare variant(bar_v1) match(construct={dispatch}) append_args(interop(target,targetsync)) +//DUMP: FunctionDecl{{.*}}bar1 'void (float *, float *)' +//DUMP: OMPDeclareVariantAttr{{.*}}construct={dispatch} Target_TargetSync +//DUMP: DeclRefExpr{{.*}}bar_v1 +#pragma omp declare variant(bar_v1) match(construct={dispatch}) \ + append_args(interop(target,targetsync)) +void bar1(float *FF1, float *FF2) { return; } + +//PRINT: #pragma omp declare variant(bar_v1) match(construct={dispatch}) append_args(interop(targetsync)) +//DUMP: FunctionDecl{{.*}}bar2 'void (float *, float *)' +//DUMP: OMPDeclareVariantAttr{{.*}}construct={dispatch} TargetSync +//DUMP: DeclRefExpr{{.*}}bar_v1 +#pragma omp declare variant(bar_v1) match(construct={dispatch}) \ + append_args(interop(targetsync)) +void bar2(float *FF1, float *FF2) { return; } + +//PRINT: #pragma omp declare variant(bar_v1) match(construct={dispatch}) append_args(interop(target)) +//DUMP: FunctionDecl{{.*}}bar3 'void (float *, float *)' +//DUMP: OMPDeclareVariantAttr{{.*}}construct={dispatch} Target +//DUMP: DeclRefExpr{{.*}}bar_v1 +#pragma omp declare variant(bar_v1) match(construct={dispatch}) \ + append_args(interop(target)) +void bar3(float *FF1, float *FF2) { return; } + +//PRINT: #pragma omp declare variant(bar_v2) match(construct={dispatch}) append_args(interop(target), interop(targetsync)) +//DUMP: FunctionDecl{{.*}}bar4 'void (float *, float *)' +//DUMP: OMPDeclareVariantAttr{{.*}}construct={dispatch} Target TargetSync +//DUMP: DeclRefExpr{{.*}}bar_v2 +#pragma omp declare variant(bar_v2) match(construct={dispatch}) \ + append_args(interop(target), interop(targetsync)) +void bar4(float *FF1, float *FF2) { return; } + +//PRINT: #pragma omp declare variant(bar_v2) match(construct={dispatch}) append_args(interop(targetsync), interop(target)) +//DUMP: FunctionDecl{{.*}}bar5 'void (float *, float *)' +//DUMP: OMPDeclareVariantAttr{{.*}}construct={dispatch} TargetSync Target +//DUMP: DeclRefExpr{{.*}}bar_v2 +#pragma omp declare variant(bar_v2) match(construct={dispatch}) \ + append_args(interop(targetsync), interop(target)) +void bar5(float *FF1, float *FF2) { return; } #endif // HEADER Index: clang/test/OpenMP/declare_variant_clauses_messages.cpp =================================================================== --- clang/test/OpenMP/declare_variant_clauses_messages.cpp +++ clang/test/OpenMP/declare_variant_clauses_messages.cpp @@ -2,11 +2,14 @@ // RUN: %clang_cc1 -verify -fopenmp -fopenmp-version=50 -DOMP50 -std=c++11 -o - %s +typedef void *omp_interop_t; + 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; } +void foo_v4(float *AAA, float *BBB, int *I, omp_interop_t) { return; } #ifdef OMP51 // expected-error@+3 {{'adjust_arg' argument 'AAA' used in multiple clauses}} @@ -36,12 +39,69 @@ // expected-error@+2 {{'adjust_args' clause requires 'dispatch' context selector}} #pragma omp declare variant(foo_v3) \ adjust_args(nothing:BBB) match(device={arch(ppc)}) + +// expected-error@+1 {{expected 'match', 'adjust_args', or 'append_args' clause on 'omp declare variant' directive}} +#pragma omp declare variant(foo_v1) + +// expected-error@+1 {{expected 'match', 'adjust_args', or 'append_args' clause on 'omp declare variant' directive}} +#pragma omp declare variant(foo_v1) other + +// expected-error@+2 {{unexpected append-op in 'append_args' clause, expected 'interop'}} +#pragma omp declare variant(foo_v1) match(construct={dispatch}) \ + append_args(foobar(target)) + +// expected-error@+2 {{directive '#pragma omp declare variant' cannot contain more than one 'append_args' clause}} +#pragma omp declare variant(foo_v1) match(construct={dispatch}) \ + append_args(interop(target)) \ + append_args(interop(targetsync)) + +// expected-error@+2 {{'append_args' clause requires 'dispatch' context selector}} +#pragma omp declare variant(foo_v4) \ + append_args(interop(target)) match(construct={target}) + +// expected-error@+2 {{'append_args' clause requires 'dispatch' context selector}} +#pragma omp declare variant(foo_v4) \ + match(construct={target}) append_args(interop(target)) + +// expected-warning@+2 {{interop type 'target' cannot be specified more than once}} +#pragma omp declare variant(foo_v4) match(construct={dispatch}) \ + append_args(interop(target,target)) + +// expected-warning@+2 {{interop type 'targetsync' cannot be specified more than once}} +#pragma omp declare variant(foo_v4) match(construct={dispatch}) \ + append_args(interop(targetsync,targetsync)) + +// expected-error@+2 {{expected interop type: 'target' and/or 'targetsync'}} +#pragma omp declare variant(foo_v4) match(construct={dispatch}) \ + append_args(interop()) + +// expected-error@+2 {{expected interop type: 'target' and/or 'targetsync'}} +#pragma omp declare variant(foo_v4) match(construct={dispatch}) \ + append_args(interop(somethingelse)) + +// expected-error@+1 {{variant in '#pragma omp declare variant' with type 'void (float *, float *, int *)' is incompatible with type 'void (float *, float *, int *)' with appended arguments}} +#pragma omp declare variant(foo_v1) match(construct={dispatch}) \ + append_args(interop(target)) + +// expected-error@+1 {{variant in '#pragma omp declare variant' with type 'void (float *, float *, int *)' is incompatible with type 'void (float *, float *, int *)' with appended arguments}} +#pragma omp declare variant(foo_v1) match(construct={dispatch}) \ + append_args(interop(target),interop(targetsync)) + +// expected-error@+1 {{variant in '#pragma omp declare variant' with type 'void (float *, float *, int *, omp_interop_t)' (aka 'void (float *, float *, int *, void *)') is incompatible with type 'void (float *, float *, int *)' with appended arguments}} +#pragma omp declare variant(foo_v4) match(construct={dispatch}) \ + append_args(interop(target),interop(targetsync)) + +// expected-error@+1 {{variant in '#pragma omp declare variant' with type 'void (float *, float *, int *, omp_interop_t)' (aka 'void (float *, float *, int *, void *)') is incompatible with type 'void (float *, float *, int *)'}} +#pragma omp declare variant(foo_v4) match(construct={dispatch}) + #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)}) +// expected-error@+2 {{expected 'match' clause on 'omp declare variant' directive}} +#pragma omp declare variant(foo_v1) \ + append_args(interop(target)) match(device={arch(arm)}) #endif // OMP50 void foo(float *AAA, float *BBB, int *I) { return; } - Index: flang/lib/Semantics/check-omp-structure.cpp =================================================================== --- flang/lib/Semantics/check-omp-structure.cpp +++ flang/lib/Semantics/check-omp-structure.cpp @@ -1423,6 +1423,7 @@ CHECK_SIMPLE_CLAUSE(Filter, OMPC_filter) CHECK_SIMPLE_CLAUSE(When, OMPC_when) CHECK_SIMPLE_CLAUSE(AdjustArgs, OMPC_adjust_args) +CHECK_SIMPLE_CLAUSE(AppendArgs, OMPC_append_args) CHECK_REQ_SCALAR_INT_CLAUSE(Grainsize, OMPC_grainsize) CHECK_REQ_SCALAR_INT_CLAUSE(NumTasks, OMPC_num_tasks) Index: llvm/include/llvm/Frontend/OpenMP/OMP.td =================================================================== --- llvm/include/llvm/Frontend/OpenMP/OMP.td +++ llvm/include/llvm/Frontend/OpenMP/OMP.td @@ -315,6 +315,7 @@ def OMPC_DeviceType : Clause<"device_type"> {} def OMPC_Match : Clause<"match"> {} def OMPC_AdjustArgs : Clause<"adjust_args"> { } +def OMPC_AppendArgs : Clause<"append_args"> { } def OMPC_Depobj : Clause<"depobj"> { let clangClass = "OMPDepobjClause"; let isImplicit = true; @@ -1520,7 +1521,8 @@ VersionedClause ]; let allowedExclusiveClauses = [ - VersionedClause + VersionedClause, + VersionedClause ]; } def OMP_MasterTaskloop : Directive<"master taskloop"> {