Index: clang/include/clang-c/Index.h =================================================================== --- clang/include/clang-c/Index.h +++ clang/include/clang-c/Index.h @@ -2580,7 +2580,11 @@ */ CXCursor_OMPInteropDirective = 290, - CXCursor_LastStmt = CXCursor_OMPInteropDirective, + /** OpenMP dispatch directive. + */ + CXCursor_OMPDispatchDirective = 291, + + CXCursor_LastStmt = CXCursor_OMPDispatchDirective, /** * Cursor that represents the translation unit itself. Index: clang/include/clang/AST/RecursiveASTVisitor.h =================================================================== --- clang/include/clang/AST/RecursiveASTVisitor.h +++ clang/include/clang/AST/RecursiveASTVisitor.h @@ -2971,6 +2971,9 @@ DEF_TRAVERSE_STMT(OMPInteropDirective, { TRY_TO(TraverseOMPExecutableDirective(S)); }) +DEF_TRAVERSE_STMT(OMPDispatchDirective, + { TRY_TO(TraverseOMPExecutableDirective(S)); }) + // OpenMP clauses. template bool RecursiveASTVisitor::TraverseOMPClause(OMPClause *C) { Index: clang/include/clang/AST/StmtOpenMP.h =================================================================== --- clang/include/clang/AST/StmtOpenMP.h +++ clang/include/clang/AST/StmtOpenMP.h @@ -5139,6 +5139,72 @@ } }; +/// This represents '#pragma omp dispatch' directive. +/// +/// \code +/// #pragma omp dispatch device(dnum) +/// \endcode +/// This example shows a directive '#pragma omp dispatch' with a +/// device clause with variable 'dnum'. +/// +class OMPDispatchDirective : public OMPExecutableDirective { + friend class ASTStmtReader; + friend class OMPExecutableDirective; + + /// The location of the target-call. + SourceLocation TargetCallLoc; + + /// Set the location of the target-call. + void setTargetCallLoc(SourceLocation Loc) { TargetCallLoc = Loc; } + + /// Build directive with the given start and end location. + /// + /// \param StartLoc Starting location of the directive kind. + /// \param EndLoc Ending location of the directive. + /// + OMPDispatchDirective(SourceLocation StartLoc, SourceLocation EndLoc) + : OMPExecutableDirective(OMPDispatchDirectiveClass, + llvm::omp::OMPD_dispatch, StartLoc, EndLoc) {} + + /// Build an empty directive. + /// + explicit OMPDispatchDirective() + : OMPExecutableDirective(OMPDispatchDirectiveClass, + llvm::omp::OMPD_dispatch, SourceLocation(), + SourceLocation()) {} + +public: + /// Creates directive with a list of \a Clauses. + /// + /// \param C AST context. + /// \param StartLoc Starting location of the directive kind. + /// \param EndLoc Ending Location of the directive. + /// \param Clauses List of clauses. + /// \param AssociatedStmt Statement, associated with the directive. + /// \param TargetCallLoc Location of the target-call. + /// + static OMPDispatchDirective * + Create(const ASTContext &C, SourceLocation StartLoc, SourceLocation EndLoc, + ArrayRef Clauses, Stmt *AssociatedStmt, + SourceLocation TargetCallLoc); + + /// Creates an empty directive with the place for \a NumClauses + /// clauses. + /// + /// \param C AST context. + /// \param NumClauses Number of clauses. + /// + static OMPDispatchDirective *CreateEmpty(const ASTContext &C, + unsigned NumClauses, EmptyShell); + + /// Return location of target-call. + SourceLocation getTargetCallLoc() { return TargetCallLoc; } + + static bool classof(const Stmt *T) { + return T->getStmtClass() == OMPDispatchDirectiveClass; + } +}; + } // end namespace clang #endif Index: clang/include/clang/Basic/DiagnosticSemaKinds.td =================================================================== --- clang/include/clang/Basic/DiagnosticSemaKinds.td +++ clang/include/clang/Basic/DiagnosticSemaKinds.td @@ -10616,6 +10616,9 @@ "'depend' clause requires the 'targetsync' interop type">; def err_omp_interop_var_multiple_actions : Error< "interop variable %0 used in multiple action clauses">; +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">; } // end of OpenMP category let CategoryName = "Related Result Type Issue" in { Index: clang/include/clang/Basic/StmtNodes.td =================================================================== --- clang/include/clang/Basic/StmtNodes.td +++ clang/include/clang/Basic/StmtNodes.td @@ -276,3 +276,4 @@ def OMPTargetTeamsDistributeParallelForSimdDirective : StmtNode; def OMPTargetTeamsDistributeSimdDirective : StmtNode; def OMPInteropDirective : StmtNode; +def OMPDispatchDirective : StmtNode; Index: clang/include/clang/Sema/Sema.h =================================================================== --- clang/include/clang/Sema/Sema.h +++ clang/include/clang/Sema/Sema.h @@ -10803,6 +10803,11 @@ StmtResult ActOnOpenMPInteropDirective(ArrayRef Clauses, SourceLocation StartLoc, SourceLocation EndLoc); + /// Called on well-formed '\#pragma omp dispatch' after parsing of the + // /associated statement. + StmtResult ActOnOpenMPDispatchDirective(ArrayRef Clauses, + Stmt *AStmt, SourceLocation StartLoc, + SourceLocation EndLoc); /// Checks correctness of linear modifiers. bool CheckOpenMPLinearModifier(OpenMPLinearClauseKind LinKind, Index: clang/include/clang/Serialization/ASTBitCodes.h =================================================================== --- clang/include/clang/Serialization/ASTBitCodes.h +++ clang/include/clang/Serialization/ASTBitCodes.h @@ -1941,6 +1941,7 @@ STMT_OMP_TARGET_TEAMS_DISTRIBUTE_PARALLEL_FOR_SIMD_DIRECTIVE, STMT_OMP_TARGET_TEAMS_DISTRIBUTE_SIMD_DIRECTIVE, STMT_OMP_INTEROP_DIRECTIVE, + STMT_OMP_DISPATCH_DIRECTIVE, EXPR_OMP_ARRAY_SECTION, EXPR_OMP_ARRAY_SHAPING, EXPR_OMP_ITERATOR, Index: clang/lib/AST/StmtOpenMP.cpp =================================================================== --- clang/lib/AST/StmtOpenMP.cpp +++ clang/lib/AST/StmtOpenMP.cpp @@ -1959,3 +1959,21 @@ EmptyShell) { return createEmptyDirective(C, NumClauses); } + +OMPDispatchDirective *OMPDispatchDirective::Create( + const ASTContext &C, SourceLocation StartLoc, SourceLocation EndLoc, + ArrayRef Clauses, Stmt *AssociatedStmt, + SourceLocation TargetCallLoc) { + auto *Dir = createDirective( + C, Clauses, AssociatedStmt, /*NumChildren=*/0, StartLoc, EndLoc); + Dir->setTargetCallLoc(TargetCallLoc); + return Dir; +} + +OMPDispatchDirective *OMPDispatchDirective::CreateEmpty(const ASTContext &C, + unsigned NumClauses, + EmptyShell) { + return createEmptyDirective(C, NumClauses, + /*HasAssociatedStmt=*/true, + /*NumChildren=*/0); +} Index: clang/lib/AST/StmtPrinter.cpp =================================================================== --- clang/lib/AST/StmtPrinter.cpp +++ clang/lib/AST/StmtPrinter.cpp @@ -967,6 +967,11 @@ PrintOMPExecutableDirective(Node); } +void StmtPrinter::VisitOMPDispatchDirective(OMPDispatchDirective *Node) { + Indent() << "#pragma omp dispatch"; + PrintOMPExecutableDirective(Node); +} + //===----------------------------------------------------------------------===// // Expr printing methods. //===----------------------------------------------------------------------===// Index: clang/lib/AST/StmtProfile.cpp =================================================================== --- clang/lib/AST/StmtProfile.cpp +++ clang/lib/AST/StmtProfile.cpp @@ -1144,6 +1144,10 @@ VisitOMPExecutableDirective(S); } +void StmtProfiler::VisitOMPDispatchDirective(const OMPDispatchDirective *S) { + VisitOMPExecutableDirective(S); +} + void StmtProfiler::VisitExpr(const Expr *S) { VisitStmt(S); } Index: clang/lib/Basic/OpenMPKinds.cpp =================================================================== --- clang/lib/Basic/OpenMPKinds.cpp +++ clang/lib/Basic/OpenMPKinds.cpp @@ -646,6 +646,9 @@ CaptureRegions.push_back(OMPD_teams); CaptureRegions.push_back(OMPD_parallel); break; + case OMPD_dispatch: + CaptureRegions.push_back(OMPD_dispatch); + break; case OMPD_simd: case OMPD_for: case OMPD_for_simd: Index: clang/lib/CodeGen/CGStmt.cpp =================================================================== --- clang/lib/CodeGen/CGStmt.cpp +++ clang/lib/CodeGen/CGStmt.cpp @@ -378,6 +378,9 @@ case Stmt::OMPInteropDirectiveClass: llvm_unreachable("Interop directive not supported yet."); break; + case Stmt::OMPDispatchDirectiveClass: + llvm_unreachable("Dispatch directive not supported yet."); + break; } } Index: clang/lib/Parse/ParseOpenMP.cpp =================================================================== --- clang/lib/Parse/ParseOpenMP.cpp +++ clang/lib/Parse/ParseOpenMP.cpp @@ -2207,6 +2207,7 @@ case OMPD_target_teams_distribute_parallel_for: case OMPD_target_teams_distribute_parallel_for_simd: case OMPD_target_teams_distribute_simd: + case OMPD_dispatch: Diag(Tok, diag::err_omp_unexpected_directive) << 1 << getOpenMPDirectiveName(DKind); break; @@ -2430,7 +2431,8 @@ case OMPD_target_teams_distribute: case OMPD_target_teams_distribute_parallel_for: case OMPD_target_teams_distribute_parallel_for_simd: - case OMPD_target_teams_distribute_simd: { + case OMPD_target_teams_distribute_simd: + case OMPD_dispatch: { // Special processing for flush and depobj clauses. Token ImplicitTok; bool ImplicitClauseAllowed = false; Index: clang/lib/Sema/SemaExceptionSpec.cpp =================================================================== --- clang/lib/Sema/SemaExceptionSpec.cpp +++ clang/lib/Sema/SemaExceptionSpec.cpp @@ -1487,6 +1487,7 @@ case Stmt::OMPTeamsDistributeParallelForSimdDirectiveClass: case Stmt::OMPTeamsDistributeSimdDirectiveClass: case Stmt::OMPInteropDirectiveClass: + case Stmt::OMPDispatchDirectiveClass: case Stmt::ReturnStmtClass: case Stmt::SEHExceptStmtClass: case Stmt::SEHFinallyStmtClass: Index: clang/lib/Sema/SemaOpenMP.cpp =================================================================== --- clang/lib/Sema/SemaOpenMP.cpp +++ clang/lib/Sema/SemaOpenMP.cpp @@ -3979,7 +3979,8 @@ case OMPD_distribute: case OMPD_distribute_simd: case OMPD_ordered: - case OMPD_target_data: { + case OMPD_target_data: + case OMPD_dispatch: { Sema::CapturedParamNameType Params[] = { std::make_pair(StringRef(), QualType()) // __context with shared vars }; @@ -6120,6 +6121,10 @@ "No associated statement allowed for 'omp interop' directive"); Res = ActOnOpenMPInteropDirective(ClausesWithImplicit, StartLoc, EndLoc); break; + case OMPD_dispatch: + Res = ActOnOpenMPDispatchDirective(ClausesWithImplicit, AStmt, StartLoc, + EndLoc); + break; case OMPD_declare_target: case OMPD_end_declare_target: case OMPD_threadprivate: @@ -9758,6 +9763,100 @@ DSAStack->isCancelRegion()); } +namespace { +class DispatchStmtExprChecker + : public StmtVisitor { + Sema &S; + bool TopLevel = true; + Expr *TargetCall = nullptr; + SourceLocation ErrorLoc; + +public: + Expr *getTargetCall() { return TargetCall; } + SourceLocation getErrorLoc() { return ErrorLoc; } + bool VisitCallExpr(CallExpr *E) { + if (E->getDirectCallee()) { + TargetCall = E; + return true; + } + ErrorLoc = E->getBeginLoc(); + return false; + } + bool VisitExprWithCleanups(ExprWithCleanups *E) { + return Visit(E->getSubExpr()); + } + bool VisitCXXBindTemporaryExpr(CXXBindTemporaryExpr *E) { + return Visit(E->getSubExpr()); + } + bool VisitMaterializeTemporaryExpr(MaterializeTemporaryExpr *E) { + return Visit(E->getSubExpr()->IgnoreParenImpCasts()); + } + bool VisitStmt(Stmt *AS) { + ErrorLoc = AS->getBeginLoc(); + return false; + } + bool VisitBinaryOperator(BinaryOperator *E) { + if (TopLevel && E->getOpcode() == BO_Assign) { + TopLevel = false; + return Visit(E->getRHS()->IgnoreParens()); + } + ErrorLoc = E->getOperatorLoc(); + return false; + } + bool VisitCastExpr(CastExpr *E) { + // Allow common cast to void to quiet warnings. + if (E->getCastKind() == CK_ToVoid) + return Visit(E->getSubExpr()->IgnoreParens()); + ErrorLoc = E->getBeginLoc(); + return false; + } + bool VisitCXXOperatorCallExpr(CXXOperatorCallExpr *E) { + if (TopLevel && E->getOperator() == OO_Equal) { + TopLevel = false; + if (Visit(E->getArg(1)->IgnoreParens())) + return true; + if (E->getDirectCallee()) { + TargetCall = E; + return true; + } + } + return VisitCallExpr(E); + } + explicit DispatchStmtExprChecker(Sema &S) : S(S) {} +}; +} // namespace + +StmtResult Sema::ActOnOpenMPDispatchDirective(ArrayRef Clauses, + Stmt *AStmt, + SourceLocation StartLoc, + SourceLocation EndLoc) { + if (!AStmt) + return StmtError(); + + Stmt *S = cast(AStmt)->getCapturedStmt(); + + // 5.1 OpenMP + // expression-stmt : an expression statement with one of the following forms: + // expression = target-call ( [expression-list] ); + // target-call ( [expression-list] ); + + SourceLocation TargetCallLoc; + DispatchStmtExprChecker Checker(*this); + if (!CurContext->isDependentContext()) { + if (!Checker.Visit(S)) { + Diag(Checker.getErrorLoc(), diag::err_omp_dispatch_statement_call); + return StmtError(); + } + assert(Checker.getTargetCall()); + TargetCallLoc = Checker.getTargetCall()->getExprLoc(); + } + + setFunctionHasBranchProtectedScope(); + + return OMPDispatchDirective::Create(Context, StartLoc, EndLoc, Clauses, AStmt, + TargetCallLoc); +} + StmtResult Sema::ActOnOpenMPSingleDirective(ArrayRef Clauses, Stmt *AStmt, SourceLocation StartLoc, @@ -13349,6 +13448,7 @@ case OMPD_target_parallel_for_simd: case OMPD_target_teams_distribute_parallel_for: case OMPD_target_teams_distribute_parallel_for_simd: + case OMPD_dispatch: CaptureRegion = OMPD_task; break; case OMPD_target_data: Index: clang/lib/Sema/TreeTransform.h =================================================================== --- clang/lib/Sema/TreeTransform.h +++ clang/lib/Sema/TreeTransform.h @@ -9069,6 +9069,17 @@ return Res; } +template +StmtResult +TreeTransform::TransformOMPDispatchDirective(OMPDispatchDirective *D) { + DeclarationNameInfo DirName; + getDerived().getSema().StartOpenMPDSABlock(OMPD_dispatch, DirName, nullptr, + D->getBeginLoc()); + StmtResult Res = getDerived().TransformOMPExecutableDirective(D); + getDerived().getSema().EndOpenMPDSABlock(Res.get()); + return Res; +} + //===----------------------------------------------------------------------===// // OpenMP clause transformation //===----------------------------------------------------------------------===// Index: clang/lib/Serialization/ASTReaderStmt.cpp =================================================================== --- clang/lib/Serialization/ASTReaderStmt.cpp +++ clang/lib/Serialization/ASTReaderStmt.cpp @@ -2593,6 +2593,12 @@ VisitOMPExecutableDirective(D); } +void ASTStmtReader::VisitOMPDispatchDirective(OMPDispatchDirective *D) { + VisitStmt(D); + VisitOMPExecutableDirective(D); + D->setTargetCallLoc(Record.readSourceLocation()); +} + //===----------------------------------------------------------------------===// // ASTReader Implementation //===----------------------------------------------------------------------===// @@ -3513,6 +3519,11 @@ Context, Record[ASTStmtReader::NumStmtFields], Empty); break; + case STMT_OMP_DISPATCH_DIRECTIVE: + S = OMPDispatchDirective::CreateEmpty( + Context, Record[ASTStmtReader::NumStmtFields], Empty); + break; + case EXPR_CXX_OPERATOR_CALL: S = CXXOperatorCallExpr::CreateEmpty( Context, /*NumArgs=*/Record[ASTStmtReader::NumExprFields], Index: clang/lib/Serialization/ASTWriterStmt.cpp =================================================================== --- clang/lib/Serialization/ASTWriterStmt.cpp +++ clang/lib/Serialization/ASTWriterStmt.cpp @@ -2547,6 +2547,13 @@ Code = serialization::STMT_OMP_INTEROP_DIRECTIVE; } +void ASTStmtWriter::VisitOMPDispatchDirective(OMPDispatchDirective *D) { + VisitStmt(D); + VisitOMPExecutableDirective(D); + Record.AddSourceLocation(D->getTargetCallLoc()); + Code = serialization::STMT_OMP_DISPATCH_DIRECTIVE; +} + //===----------------------------------------------------------------------===// // ASTWriter Implementation //===----------------------------------------------------------------------===// Index: clang/lib/StaticAnalyzer/Core/ExprEngine.cpp =================================================================== --- clang/lib/StaticAnalyzer/Core/ExprEngine.cpp +++ clang/lib/StaticAnalyzer/Core/ExprEngine.cpp @@ -1295,6 +1295,7 @@ case Stmt::OMPTargetTeamsDistributeSimdDirectiveClass: case Stmt::OMPTileDirectiveClass: case Stmt::OMPInteropDirectiveClass: + case Stmt::OMPDispatchDirectiveClass: case Stmt::CapturedStmtClass: { const ExplodedNode *node = Bldr.generateSink(S, Pred, Pred->getState()); Engine.addAbortedBlock(node, currBldrCtx->getBlock()); Index: clang/test/OpenMP/dispatch_ast_print.cpp =================================================================== --- /dev/null +++ clang/test/OpenMP/dispatch_ast_print.cpp @@ -0,0 +1,215 @@ +// RUN: %clang_cc1 -triple=x86_64-pc-win32 -fopenmp -fopenmp-version=51 \ +// RUN: -fsyntax-only -verify %s + +// RUN: %clang_cc1 -triple x86_64-pc-linux-gnu -fopenmp -fopenmp-version=51 \ +// RUN: -fsyntax-only -verify %s + +// expected-no-diagnostics + +// RUN: %clang_cc1 -triple x86_64-pc-linux-gnu -fopenmp -fopenmp-version=51 \ +// RUN: -ast-print %s | FileCheck %s --check-prefix=PRINT + +// RUN: %clang_cc1 -triple x86_64-pc-linux-gnu -fopenmp -fopenmp-version=51 \ +// RUN: -ast-dump %s | FileCheck %s --check-prefix=DUMP + +// RUN: %clang_cc1 -triple x86_64-pc-linux-gnu -fopenmp -fopenmp-version=51 \ +// RUN: -emit-pch -o %t %s + +// RUN: %clang_cc1 -triple x86_64-pc-linux-gnu -fopenmp -fopenmp-version=51 \ +// RUN: -include-pch %t -ast-dump-all %s | FileCheck %s --check-prefix=DUMP + +// RUN: %clang_cc1 -triple x86_64-pc-linux-gnu -fopenmp -fopenmp-version=51 \ +// RUN: -include-pch %t -ast-print %s | FileCheck %s --check-prefix=PRINT + +#ifndef HEADER +#define HEADER + +int foo_gpu(int A, int *B) { return 0;} +//PRINT: #pragma omp declare variant(foo_gpu) +//DUMP: FunctionDecl{{.*}} foo +//DUMP: OMPDeclareVariantAttr {{.*}}Implicit construct{{.*}} +#pragma omp declare variant(foo_gpu) \ + match(construct={dispatch}, device={arch(arm)}) +int foo(int, int*); + +template +void fooTemp() { + T a; + TP b; + //PRINT: #pragma omp dispatch nowait + //DUMP: OMPDispatchDirective + //DUMP: OMPNowaitClause + #pragma omp dispatch nowait + foo(a, b); +} + +int *get_device_ptr(); +int get_device(); +int other(); + +//DUMP: FunctionDecl{{.*}} test_one +void test_one() +{ + int aaa, bbb, var; + //PRINT: #pragma omp dispatch depend(in : var) nowait + //DUMP: OMPDispatchDirective + //DUMP: OMPDependClause + //DUMP: OMPNowaitClause + #pragma omp dispatch depend(in:var) nowait + foo(aaa, &bbb); + + int *dp = get_device_ptr(); + int dev = get_device(); + //PRINT: #pragma omp dispatch device(dev) is_device_ptr(dp) + //DUMP: OMPDispatchDirective + //DUMP: OMPDeviceClause + //DUMP: OMPIs_device_ptrClause + #pragma omp dispatch device(dev) is_device_ptr(dp) + foo(aaa, dp); + + //PRINT: #pragma omp dispatch + //PRINT: foo(other(), &bbb); + //DUMP: OMPDispatchDirective + #pragma omp dispatch + foo(other(), &bbb); + + fooTemp(); +} + +struct Obj { + Obj(); + ~Obj(); + int disp_method_variant1(); + #pragma omp declare variant(disp_method_variant1) \ + match(construct={dispatch}, device={arch(arm)}) + int disp_method1(); + + static int disp_method_variant2() { return 1; } + #pragma omp declare variant(disp_method_variant2) \ + match(construct={dispatch}, device={arch(arm)}) + static int disp_method2() { return 2; } +}; + +Obj foo_vari(); +#pragma omp declare variant(foo_vari) \ + match(construct={dispatch}, device={arch(arm)}) +Obj foo_obj(); + +//DUMP: FunctionDecl{{.*}} test_two +void test_two(Obj o1, Obj &o2, Obj *o3) +{ + //PRINT: #pragma omp dispatch + //PRINT: o1.disp_method1(); + //DUMP: OMPDispatchDirective + #pragma omp dispatch + o1.disp_method1(); + + //PRINT: #pragma omp dispatch + //PRINT: o2.disp_method1(); + //DUMP: OMPDispatchDirective + #pragma omp dispatch + o2.disp_method1(); + + //PRINT: #pragma omp dispatch + //PRINT: o3->disp_method1(); + //DUMP: OMPDispatchDirective + #pragma omp dispatch + o3->disp_method1(); + + //PRINT: #pragma omp dispatch + //PRINT: Obj::disp_method2(); + //DUMP: OMPDispatchDirective + #pragma omp dispatch + Obj::disp_method2(); + + int ret; + //PRINT: #pragma omp dispatch + //PRINT: ret = o1.disp_method1(); + //DUMP: OMPDispatchDirective + #pragma omp dispatch + ret = o1.disp_method1(); + + //PRINT: #pragma omp dispatch + //PRINT: ret = o2.disp_method1(); + //DUMP: OMPDispatchDirective + #pragma omp dispatch + ret = o2.disp_method1(); + + //PRINT: #pragma omp dispatch + //PRINT: ret = o3->disp_method1(); + //DUMP: OMPDispatchDirective + #pragma omp dispatch + ret = o3->disp_method1(); + + //PRINT: #pragma omp dispatch + //PRINT: ret = Obj::disp_method2(); + //DUMP: OMPDispatchDirective + #pragma omp dispatch + ret = Obj::disp_method2(); + + //PRINT: #pragma omp dispatch + //PRINT: (void)Obj::disp_method2(); + //DUMP: OMPDispatchDirective + #pragma omp dispatch + (void)Obj::disp_method2(); + + // Full C++ operator= case with temps and EH. + Obj o; + //PRINT: #pragma omp dispatch + //PRINT: o = foo_obj(); + //DUMP: OMPDispatchDirective + #pragma omp dispatch + o = foo_obj(); +} + +struct A { + A& disp_operator(A other); + #pragma omp declare variant(disp_operator) \ + match(construct={dispatch}, device={arch(arm)}) + A& operator=(A other); +}; + +struct Obj2 { + A xx; + Obj2& disp_operator(Obj2 other); + #pragma omp declare variant(disp_operator) \ + match(construct={dispatch}, device={arch(arm)}) + Obj2& operator=(Obj2 other); + + void foo() { + Obj2 z; + //PRINT: #pragma omp dispatch + //PRINT: z = z; + //DUMP: OMPDispatchDirective + #pragma omp dispatch + z = z; + //PRINT: #pragma omp dispatch + //PRINT: z.operator=(z); + //DUMP: OMPDispatchDirective + #pragma omp dispatch + z.operator=(z); + } + void bar() { + Obj2 j; + //PRINT: #pragma omp dispatch + //PRINT: j = {this->xx}; + //DUMP: OMPDispatchDirective + #pragma omp dispatch + j = {this->xx}; + //PRINT: #pragma omp dispatch + //PRINT: j.operator=({this->xx}); + //DUMP: OMPDispatchDirective + #pragma omp dispatch + j.operator=({this->xx}); + } +}; + +void test_three() +{ + Obj2 z1, z; + #pragma omp dispatch + z1 = z; + #pragma omp dispatch + z1.operator=(z); +} +#endif // HEADER Index: clang/test/OpenMP/dispatch_messages.cpp =================================================================== --- /dev/null +++ clang/test/OpenMP/dispatch_messages.cpp @@ -0,0 +1,76 @@ +// RUN: %clang_cc1 -triple=x86_64-pc-win32 -verify -fopenmp \ +// RUN: -x c++ -std=c++14 -fexceptions -fcxx-exceptions %s + +// RUN: %clang_cc1 -triple=x86_64-pc-linux-gnu -verify -fopenmp \ +// RUN: -x c++ -std=c++14 -fexceptions -fcxx-exceptions %s + +int disp_variant(); +#pragma omp declare variant(disp_variant) \ + match(construct = {dispatch}, device = {arch(arm)}) +int disp_call(); + +struct Obj { + int disp_method_variant1(); + #pragma omp declare variant(disp_method_variant1) \ + match(construct={dispatch}, device={arch(arm)}) + int disp_method1(); + int disp_method_variant2(); + #pragma omp declare variant(disp_method_variant2) \ + match(construct={dispatch}, device={arch(arm)}) + int disp_method2(); +}; + +void testit_one(int dnum) { + // expected-error@+1 {{cannot contain more than one 'device' clause}} + #pragma omp dispatch device(dnum) device(3) + disp_call(); + + // expected-error@+1 {{cannot contain more than one 'nowait' clause}} + #pragma omp dispatch nowait device(dnum) nowait + disp_call(); +} + +void testit_two() { + //expected-error@+2 {{cannot return from OpenMP region}} + #pragma omp dispatch + return disp_call(); +} + +void testit_three(int (*fptr)(void), Obj *obj, int (Obj::*mptr)(void)) { + //expected-error@+2 {{statement after '#pragma omp dispatch' must be a direct call to a target function or an assignment to one}} + #pragma omp dispatch + fptr(); + + //expected-error@+2 {{statement after '#pragma omp dispatch' must be a direct call to a target function or an assignment to one}} + #pragma omp dispatch + (obj->*mptr)(); + + int ret; + + //expected-error@+2 {{statement after '#pragma omp dispatch' must be a direct call to a target function or an assignment to one}} + #pragma omp dispatch + ret = fptr(); + + //expected-error@+2 {{statement after '#pragma omp dispatch' must be a direct call to a target function or an assignment to one}} + #pragma omp dispatch + ret = (obj->*mptr)(); +} + +void testit_four(int *x, int y, Obj *obj) +{ + //expected-error@+2 {{statement after '#pragma omp dispatch' must be a direct call to a target function or an assignment to one}} + #pragma omp dispatch + *x = y; + + //expected-error@+2 {{statement after '#pragma omp dispatch' must be a direct call to a target function or an assignment to one}} + #pragma omp dispatch + y = disp_call() + disp_call(); + + //expected-error@+2 {{statement after '#pragma omp dispatch' must be a direct call to a target function or an assignment to one}} + #pragma omp dispatch + y = (y = disp_call()); + + //expected-error@+2 {{statement after '#pragma omp dispatch' must be a direct call to a target function or an assignment to one}} + #pragma omp dispatch + y += disp_call(); +} Index: clang/tools/libclang/CIndex.cpp =================================================================== --- clang/tools/libclang/CIndex.cpp +++ clang/tools/libclang/CIndex.cpp @@ -5668,6 +5668,8 @@ return cxstring::createRef("OMPTargetTeamsDistributeSimdDirective"); case CXCursor_OMPInteropDirective: return cxstring::createRef("OMPInteropDirective"); + case CXCursor_OMPDispatchDirective: + return cxstring::createRef("OMPDispatchDirective"); case CXCursor_OverloadCandidate: return cxstring::createRef("OverloadCandidate"); case CXCursor_TypeAliasTemplateDecl: Index: clang/tools/libclang/CXCursor.cpp =================================================================== --- clang/tools/libclang/CXCursor.cpp +++ clang/tools/libclang/CXCursor.cpp @@ -810,6 +810,9 @@ case Stmt::OMPInteropDirectiveClass: K = CXCursor_OMPInteropDirective; break; + case Stmt::OMPDispatchDirectiveClass: + K = CXCursor_OMPDispatchDirective; + break; case Stmt::BuiltinBitCastExprClass: K = CXCursor_BuiltinBitCastExpr; } Index: llvm/include/llvm/Frontend/OpenMP/OMP.td =================================================================== --- llvm/include/llvm/Frontend/OpenMP/OMP.td +++ llvm/include/llvm/Frontend/OpenMP/OMP.td @@ -1655,6 +1655,14 @@ VersionedClause, ]; } +def OMP_dispatch : Directive<"dispatch"> { + let allowedClauses = [ + VersionedClause, + VersionedClause, + VersionedClause, + VersionedClause + ]; +} def OMP_Unknown : Directive<"unknown"> { let isDefault = true; } Index: llvm/include/llvm/Frontend/OpenMP/OMPKinds.def =================================================================== --- llvm/include/llvm/Frontend/OpenMP/OMPKinds.def +++ llvm/include/llvm/Frontend/OpenMP/OMPKinds.def @@ -1078,6 +1078,7 @@ __OMP_TRAIT_PROPERTY(user, condition, false) __OMP_TRAIT_PROPERTY(user, condition, unknown) +__OMP_TRAIT_SELECTOR_AND_PROPERTY(construct, dispatch) // Note that we put isa last so that the other conditions are checked first. // This allows us to issue warnings wrt. isa only if we match otherwise.