Added basic parsing/sema/serialization support for dispatch directive.
Differential Revision: https://reviews.llvm.org/D99537
*/
CXCursor_OMPInteropDirective = 290,
- CXCursor_LastStmt = CXCursor_OMPInteropDirective,
+ /** OpenMP dispatch directive.
+ */
+ CXCursor_OMPDispatchDirective = 291,
+
+ CXCursor_LastStmt = CXCursor_OMPDispatchDirective,
/**
* Cursor that represents the translation unit itself.
DEF_TRAVERSE_STMT(OMPInteropDirective,
{ TRY_TO(TraverseOMPExecutableDirective(S)); })
+DEF_TRAVERSE_STMT(OMPDispatchDirective,
+ { TRY_TO(TraverseOMPExecutableDirective(S)); })
+
// OpenMP clauses.
template <typename Derived>
bool RecursiveASTVisitor<Derived>::TraverseOMPClause(OMPClause *C) {
}
};
+/// 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 final : 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<OMPClause *> 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() const { return TargetCallLoc; }
+
+ static bool classof(const Stmt *T) {
+ return T->getStmtClass() == OMPDispatchDirectiveClass;
+ }
+};
+
} // end namespace clang
#endif
"'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 {
def OMPTargetTeamsDistributeParallelForSimdDirective : StmtNode<OMPLoopDirective>;
def OMPTargetTeamsDistributeSimdDirective : StmtNode<OMPLoopDirective>;
def OMPInteropDirective : StmtNode<OMPExecutableDirective>;
+def OMPDispatchDirective : StmtNode<OMPExecutableDirective>;
StmtResult ActOnOpenMPInteropDirective(ArrayRef<OMPClause *> Clauses,
SourceLocation StartLoc,
SourceLocation EndLoc);
+ /// Called on well-formed '\#pragma omp dispatch' after parsing of the
+ // /associated statement.
+ StmtResult ActOnOpenMPDispatchDirective(ArrayRef<OMPClause *> Clauses,
+ Stmt *AStmt, SourceLocation StartLoc,
+ SourceLocation EndLoc);
/// Checks correctness of linear modifiers.
bool CheckOpenMPLinearModifier(OpenMPLinearClauseKind LinKind,
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,
EmptyShell) {
return createEmptyDirective<OMPInteropDirective>(C, NumClauses);
}
+
+OMPDispatchDirective *OMPDispatchDirective::Create(
+ const ASTContext &C, SourceLocation StartLoc, SourceLocation EndLoc,
+ ArrayRef<OMPClause *> Clauses, Stmt *AssociatedStmt,
+ SourceLocation TargetCallLoc) {
+ auto *Dir = createDirective<OMPDispatchDirective>(
+ C, Clauses, AssociatedStmt, /*NumChildren=*/0, StartLoc, EndLoc);
+ Dir->setTargetCallLoc(TargetCallLoc);
+ return Dir;
+}
+
+OMPDispatchDirective *OMPDispatchDirective::CreateEmpty(const ASTContext &C,
+ unsigned NumClauses,
+ EmptyShell) {
+ return createEmptyDirective<OMPDispatchDirective>(C, NumClauses,
+ /*HasAssociatedStmt=*/true,
+ /*NumChildren=*/0);
+}
PrintOMPExecutableDirective(Node);
}
+void StmtPrinter::VisitOMPDispatchDirective(OMPDispatchDirective *Node) {
+ Indent() << "#pragma omp dispatch";
+ PrintOMPExecutableDirective(Node);
+}
+
//===----------------------------------------------------------------------===//
// Expr printing methods.
//===----------------------------------------------------------------------===//
VisitOMPExecutableDirective(S);
}
+void StmtProfiler::VisitOMPDispatchDirective(const OMPDispatchDirective *S) {
+ VisitOMPExecutableDirective(S);
+}
+
void StmtProfiler::VisitExpr(const Expr *S) {
VisitStmt(S);
}
case OMPD_atomic:
case OMPD_target_data:
case OMPD_distribute_simd:
+ case OMPD_dispatch:
CaptureRegions.push_back(OMPD_unknown);
break;
case OMPD_tile:
case Stmt::OMPInteropDirectiveClass:
llvm_unreachable("Interop directive not supported yet.");
break;
+ case Stmt::OMPDispatchDirectiveClass:
+ llvm_unreachable("Dispatch directive not supported yet.");
+ break;
}
}
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;
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;
case Stmt::OMPTeamsDistributeParallelForSimdDirectiveClass:
case Stmt::OMPTeamsDistributeSimdDirectiveClass:
case Stmt::OMPInteropDirectiveClass:
+ case Stmt::OMPDispatchDirectiveClass:
case Stmt::ReturnStmtClass:
case Stmt::SEHExceptStmtClass:
case Stmt::SEHFinallyStmtClass:
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
};
"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:
DSAStack->isCancelRegion());
}
+static Expr *getDirectCallExpr(Expr *E) {
+ E = E->IgnoreParenCasts()->IgnoreImplicit();
+ if (auto *CE = dyn_cast<CallExpr>(E))
+ if (CE->getDirectCallee())
+ return E;
+ return nullptr;
+}
+
+StmtResult Sema::ActOnOpenMPDispatchDirective(ArrayRef<OMPClause *> Clauses,
+ Stmt *AStmt,
+ SourceLocation StartLoc,
+ SourceLocation EndLoc) {
+ if (!AStmt)
+ return StmtError();
+
+ Stmt *S = cast<CapturedStmt>(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;
+
+ if (!CurContext->isDependentContext()) {
+ Expr *TargetCall = nullptr;
+
+ auto *E = dyn_cast<Expr>(S);
+ if (!E) {
+ Diag(S->getBeginLoc(), diag::err_omp_dispatch_statement_call);
+ return StmtError();
+ }
+
+ E = E->IgnoreParenCasts()->IgnoreImplicit();
+
+ if (auto *BO = dyn_cast<BinaryOperator>(E)) {
+ if (BO->getOpcode() == BO_Assign)
+ TargetCall = getDirectCallExpr(BO->getRHS());
+ } else {
+ if (auto *COCE = dyn_cast<CXXOperatorCallExpr>(E))
+ if (COCE->getOperator() == OO_Equal)
+ TargetCall = getDirectCallExpr(COCE->getArg(1));
+ if (!TargetCall)
+ TargetCall = getDirectCallExpr(E);
+ }
+ if (!TargetCall) {
+ Diag(E->getBeginLoc(), diag::err_omp_dispatch_statement_call);
+ return StmtError();
+ }
+ TargetCallLoc = TargetCall->getExprLoc();
+ }
+
+ setFunctionHasBranchProtectedScope();
+
+ return OMPDispatchDirective::Create(Context, StartLoc, EndLoc, Clauses, AStmt,
+ TargetCallLoc);
+}
+
StmtResult Sema::ActOnOpenMPSingleDirective(ArrayRef<OMPClause *> Clauses,
Stmt *AStmt,
SourceLocation StartLoc,
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:
return Res;
}
+template <typename Derived>
+StmtResult
+TreeTransform<Derived>::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
//===----------------------------------------------------------------------===//
VisitOMPExecutableDirective(D);
}
+void ASTStmtReader::VisitOMPDispatchDirective(OMPDispatchDirective *D) {
+ VisitStmt(D);
+ VisitOMPExecutableDirective(D);
+ D->setTargetCallLoc(Record.readSourceLocation());
+}
+
//===----------------------------------------------------------------------===//
// ASTReader Implementation
//===----------------------------------------------------------------------===//
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],
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
//===----------------------------------------------------------------------===//
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());
--- /dev/null
+// 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 <typename T, typename TP>
+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<int, int*>();
+}
+
+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
--- /dev/null
+// 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();
+
+ //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
+ for (int I = 0; I < 8; ++I) {
+ disp_call();
+ }
+}
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:
case Stmt::OMPInteropDirectiveClass:
K = CXCursor_OMPInteropDirective;
break;
+ case Stmt::OMPDispatchDirectiveClass:
+ K = CXCursor_OMPDispatchDirective;
+ break;
case Stmt::BuiltinBitCastExprClass:
K = CXCursor_BuiltinBitCastExpr;
}
VersionedClause<OMPC_Use>,
];
}
+def OMP_dispatch : Directive<"dispatch"> {
+ let allowedClauses = [
+ VersionedClause<OMPC_Device>,
+ VersionedClause<OMPC_IsDevicePtr>,
+ VersionedClause<OMPC_NoWait>,
+ VersionedClause<OMPC_Depend>
+ ];
+}
def OMP_Unknown : Directive<"unknown"> {
let isDefault = true;
}
__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.