Added basic parsing/sema/serialization support for interop directive.
Support for the 'init' clause.
Differential Revision: https://reviews.llvm.org/D98558
*/
CXCursor_OMPCanonicalLoop = 289,
- CXCursor_LastStmt = CXCursor_OMPCanonicalLoop,
+ /** OpenMP interop directive.
+ */
+ CXCursor_OMPInteropDirective = 290,
+
+ CXCursor_LastStmt = CXCursor_OMPInteropDirective,
/**
* Cursor that represents the translation unit itself.
}
};
+/// This represents the 'init' clause in '#pragma omp ...' directives.
+///
+/// \code
+/// #pragma omp interop init(target:obj)
+/// \endcode
+class OMPInitClause final
+ : public OMPVarListClause<OMPInitClause>,
+ private llvm::TrailingObjects<OMPInitClause, Expr *> {
+ friend class OMPClauseReader;
+ friend OMPVarListClause;
+ friend TrailingObjects;
+
+ /// Location of interop variable.
+ SourceLocation VarLoc;
+
+ bool IsTarget = false;
+ bool IsTargetSync = false;
+
+ void setInteropVar(Expr *E) { varlist_begin()[0] = E; }
+
+ void setIsTarget(bool V) { IsTarget = V; }
+
+ void setIsTargetSync(bool V) { IsTargetSync = V; }
+
+ /// Sets the location of the interop variable.
+ void setVarLoc(SourceLocation Loc) { VarLoc = Loc; }
+
+ /// Build 'init' clause.
+ ///
+ /// \param IsTarget Uses the 'target' interop-type.
+ /// \param IsTargetSync Uses the 'targetsync' interop-type.
+ /// \param StartLoc Starting location of the clause.
+ /// \param LParenLoc Location of '('.
+ /// \param VarLoc Location of the interop variable.
+ /// \param EndLoc Ending location of the clause.
+ /// \param N Number of expressions.
+ OMPInitClause(bool IsTarget, bool IsTargetSync, SourceLocation StartLoc,
+ SourceLocation LParenLoc, SourceLocation VarLoc,
+ SourceLocation EndLoc, unsigned N)
+ : OMPVarListClause<OMPInitClause>(llvm::omp::OMPC_init, StartLoc,
+ LParenLoc, EndLoc, N),
+ VarLoc(VarLoc), IsTarget(IsTarget), IsTargetSync(IsTargetSync) {}
+
+ /// Build an empty clause.
+ OMPInitClause(unsigned N)
+ : OMPVarListClause<OMPInitClause>(llvm::omp::OMPC_init, SourceLocation(),
+ SourceLocation(), SourceLocation(), N) {
+ }
+
+public:
+ /// Creates a fully specified clause.
+ ///
+ /// \param C AST context.
+ /// \param InteropVar The interop variable.
+ /// \param PrefExprs The list of preference expressions.
+ /// \param IsTarget Uses the 'target' interop-type.
+ /// \param IsTargetSync Uses the 'targetsync' interop-type.
+ /// \param StartLoc Starting location of the clause.
+ /// \param LParenLoc Location of '('.
+ /// \param VarLoc Location of the interop variable.
+ /// \param EndLoc Ending location of the clause.
+ static OMPInitClause *Create(const ASTContext &C, Expr *InteropVar,
+ ArrayRef<Expr *> PrefExprs, bool IsTarget,
+ bool IsTargetSync, SourceLocation StartLoc,
+ SourceLocation LParenLoc, SourceLocation VarLoc,
+ SourceLocation EndLoc);
+
+ /// Creates an empty clause with \a N expressions.
+ ///
+ /// \param C AST context.
+ /// \param N Number of expression items.
+ static OMPInitClause *CreateEmpty(const ASTContext &C, unsigned N);
+
+ /// Returns the location of the interop variable.
+ SourceLocation getVarLoc() const { return VarLoc; }
+
+ /// Returns the interop variable.
+ Expr *getInteropVar() { return varlist_begin()[0]; }
+ const Expr *getInteropVar() const { return varlist_begin()[0]; }
+
+ /// Returns true is interop-type 'target' is used.
+ bool getIsTarget() const { return IsTarget; }
+
+ /// Returns true is interop-type 'targetsync' is used.
+ bool getIsTargetSync() const { return IsTargetSync; }
+
+ child_range children() {
+ return child_range(reinterpret_cast<Stmt **>(varlist_begin()),
+ reinterpret_cast<Stmt **>(varlist_end()));
+ }
+
+ const_child_range children() const {
+ auto Children = const_cast<OMPInitClause *>(this)->children();
+ return const_child_range(Children.begin(), Children.end());
+ }
+
+ child_range used_children() {
+ return child_range(child_iterator(), child_iterator());
+ }
+ const_child_range used_children() const {
+ return const_child_range(const_child_iterator(), const_child_iterator());
+ }
+
+ using prefs_iterator = MutableArrayRef<Expr *>::iterator;
+ using const_prefs_iterator = ArrayRef<const Expr *>::iterator;
+ using prefs_range = llvm::iterator_range<prefs_iterator>;
+ using const_prefs_range = llvm::iterator_range<const_prefs_iterator>;
+
+ prefs_range prefs() {
+ return prefs_range(reinterpret_cast<Expr **>(std::next(varlist_begin())),
+ reinterpret_cast<Expr **>(varlist_end()));
+ }
+
+ const_prefs_range prefs() const {
+ auto Prefs = const_cast<OMPInitClause *>(this)->prefs();
+ return const_prefs_range(Prefs.begin(), Prefs.end());
+ }
+
+ static bool classof(const OMPClause *T) {
+ return T->getClauseKind() == llvm::omp::OMPC_init;
+ }
+};
+
/// This represents 'destroy' clause in the '#pragma omp depobj'
/// directive.
///
DEF_TRAVERSE_STMT(OMPTargetTeamsDistributeSimdDirective,
{ TRY_TO(TraverseOMPExecutableDirective(S)); })
+DEF_TRAVERSE_STMT(OMPInteropDirective,
+ { TRY_TO(TraverseOMPExecutableDirective(S)); })
+
// OpenMP clauses.
template <typename Derived>
bool RecursiveASTVisitor<Derived>::TraverseOMPClause(OMPClause *C) {
}
template <typename Derived>
+bool RecursiveASTVisitor<Derived>::VisitOMPInitClause(OMPInitClause *C) {
+ TRY_TO(VisitOMPClauseList(C));
+ return true;
+}
+
+template <typename Derived>
bool RecursiveASTVisitor<Derived>::VisitOMPDestroyClause(OMPDestroyClause *) {
return true;
}
}
};
+/// This represents '#pragma omp interop' directive.
+///
+/// \code
+/// #pragma omp interop init(target:obj) device(x) depend(inout:y) nowait
+/// \endcode
+/// In this example directive '#pragma omp interop' has
+/// clauses 'init', 'device', 'depend' and 'nowait'.
+///
+class OMPInteropDirective final : public OMPExecutableDirective {
+ friend class ASTStmtReader;
+ friend class OMPExecutableDirective;
+
+ /// Build directive with the given start and end location.
+ ///
+ /// \param StartLoc Starting location of the directive.
+ /// \param EndLoc Ending location of the directive.
+ ///
+ OMPInteropDirective(SourceLocation StartLoc, SourceLocation EndLoc)
+ : OMPExecutableDirective(OMPInteropDirectiveClass,
+ llvm::omp::OMPD_interop, StartLoc, EndLoc) {}
+
+ /// Build an empty directive.
+ ///
+ explicit OMPInteropDirective()
+ : OMPExecutableDirective(OMPInteropDirectiveClass,
+ llvm::omp::OMPD_interop, SourceLocation(),
+ SourceLocation()) {}
+
+public:
+ /// Creates directive.
+ ///
+ /// \param C AST context.
+ /// \param StartLoc Starting location of the directive.
+ /// \param EndLoc Ending Location of the directive.
+ /// \param Clauses The directive's clauses.
+ ///
+ static OMPInteropDirective *Create(const ASTContext &C,
+ SourceLocation StartLoc,
+ SourceLocation EndLoc,
+ ArrayRef<OMPClause *> Clauses);
+
+ /// Creates an empty directive.
+ ///
+ /// \param C AST context.
+ ///
+ static OMPInteropDirective *CreateEmpty(const ASTContext &C,
+ unsigned NumClauses, EmptyShell);
+
+ static bool classof(const Stmt *T) {
+ return T->getStmtClass() == OMPInteropDirectiveClass;
+ }
+};
+
} // end namespace clang
#endif
"only a single match extension allowed per OpenMP context selector">;
def err_omp_invalid_dsa: Error<
"data-sharing attribute '%0' in '%1' clause requires OpenMP version %2 or above">;
+def err_omp_expected_punc_after_interop_mod : Error<
+ "expected ',' after interop modifier">;
+def err_omp_expected_interop_type : Error<
+ "expected interop type: 'target' and/or 'targetsync'">;
+def warn_omp_more_one_interop_type
+ : Warning<"interop type '%0' cannot be specified more than once">,
+ InGroup<OpenMPClauses>;
// Pragma loop support.
def err_pragma_loop_missing_argument : Error<
: Note<"jump bypasses OpenMP structured block">;
def note_omp_exits_structured_block
: Note<"jump exits scope of OpenMP structured block">;
+def err_omp_interop_variable_expected : Error<
+ "expected%select{| non-const}0 variable of type 'omp_interop_t'">;
+def err_omp_interop_variable_wrong_type : Error<
+ "interop variable must be of type 'omp_interop_t'">;
+def err_omp_interop_prefer_type : Error<
+ "prefer_list item must be a string literal or constant integral "
+ "expression">;
+def err_omp_interop_bad_depend_clause : Error<
+ "'depend' clause requires the 'targetsync' interop type">;
+def err_omp_interop_var_multiple_actions : Error<
+ "interop variable %0 used in multiple action clauses">;
} // end of OpenMP category
let CategoryName = "Related Result Type Issue" in {
def OMPTargetTeamsDistributeParallelForDirective : StmtNode<OMPLoopDirective>;
def OMPTargetTeamsDistributeParallelForSimdDirective : StmtNode<OMPLoopDirective>;
def OMPTargetTeamsDistributeSimdDirective : StmtNode<OMPLoopDirective>;
+def OMPInteropDirective : StmtNode<OMPExecutableDirective>;
/// '(' { <allocator> [ '(' <allocator_traits> ')' ] }+ ')'
OMPClause *ParseOpenMPUsesAllocatorClause(OpenMPDirectiveKind DKind);
+ /// Parses clause with an interop variable of kind \a Kind.
+ ///
+ /// \param Kind Kind of current clause.
+ /// \param ParseOnly true to skip the clause's semantic actions and return
+ /// nullptr.
+ //
+ OMPClause *ParseOpenMPInteropClause(OpenMPClauseKind Kind, bool ParseOnly);
+
public:
/// Parses simple expression in parens for single-expression clauses of OpenMP
/// constructs.
StmtResult ActOnOpenMPTargetTeamsDistributeSimdDirective(
ArrayRef<OMPClause *> Clauses, Stmt *AStmt, SourceLocation StartLoc,
SourceLocation EndLoc, VarsWithInheritedDSAType &VarsWithImplicitDSA);
+ /// Called on well-formed '\#pragma omp interop'.
+ StmtResult ActOnOpenMPInteropDirective(ArrayRef<OMPClause *> Clauses,
+ SourceLocation StartLoc,
+ SourceLocation EndLoc);
/// Checks correctness of linear modifiers.
bool CheckOpenMPLinearModifier(OpenMPLinearClauseKind LinKind,
/// Called on well-formed 'relaxed' clause.
OMPClause *ActOnOpenMPRelaxedClause(SourceLocation StartLoc,
SourceLocation EndLoc);
+
+ /// Called on well-formed 'init' clause.
+ OMPClause *ActOnOpenMPInitClause(Expr *InteropVar, ArrayRef<Expr *> PrefExprs,
+ bool IsTarget, bool IsTargetSync,
+ SourceLocation StartLoc,
+ SourceLocation LParenLoc,
+ SourceLocation VarLoc,
+ SourceLocation EndLoc);
+
/// Called on well-formed 'destroy' clause.
OMPClause *ActOnOpenMPDestroyClause(SourceLocation StartLoc,
SourceLocation EndLoc);
STMT_OMP_TARGET_TEAMS_DISTRIBUTE_PARALLEL_FOR_DIRECTIVE,
STMT_OMP_TARGET_TEAMS_DISTRIBUTE_PARALLEL_FOR_SIMD_DIRECTIVE,
STMT_OMP_TARGET_TEAMS_DISTRIBUTE_SIMD_DIRECTIVE,
+ STMT_OMP_INTEROP_DIRECTIVE,
EXPR_OMP_ARRAY_SECTION,
EXPR_OMP_ARRAY_SHAPING,
EXPR_OMP_ITERATOR,
return new (Mem) OMPAffinityClause(N);
}
+OMPInitClause *OMPInitClause::Create(const ASTContext &C, Expr *InteropVar,
+ ArrayRef<Expr *> PrefExprs, bool IsTarget,
+ bool IsTargetSync, SourceLocation StartLoc,
+ SourceLocation LParenLoc,
+ SourceLocation VarLoc,
+ SourceLocation EndLoc) {
+
+ void *Mem = C.Allocate(totalSizeToAlloc<Expr *>(PrefExprs.size() + 1));
+ auto *Clause =
+ new (Mem) OMPInitClause(IsTarget, IsTargetSync, StartLoc, LParenLoc,
+ VarLoc, EndLoc, PrefExprs.size() + 1);
+ Clause->setInteropVar(InteropVar);
+ llvm::copy(PrefExprs, Clause->getTrailingObjects<Expr *>() + 1);
+ return Clause;
+}
+
+OMPInitClause *OMPInitClause::CreateEmpty(const ASTContext &C, unsigned N) {
+ void *Mem = C.Allocate(totalSizeToAlloc<Expr *>(N));
+ return new (Mem) OMPInitClause(N);
+}
+
//===----------------------------------------------------------------------===//
// OpenMP clauses printing methods
//===----------------------------------------------------------------------===//
OS << ")";
}
+void OMPClausePrinter::VisitOMPInitClause(OMPInitClause *Node) {
+ OS << "init(";
+ bool First = true;
+ for (const Expr *E : Node->prefs()) {
+ if (First)
+ OS << "prefer_type(";
+ else
+ OS << ",";
+ E->printPretty(OS, nullptr, Policy);
+ First = false;
+ }
+ if (!First)
+ OS << "), ";
+ if (Node->getIsTarget())
+ OS << "target";
+ if (Node->getIsTargetSync()) {
+ if (Node->getIsTarget())
+ OS << ", ";
+ OS << "targetsync";
+ }
+ OS << " : ";
+ Node->getInteropVar()->printPretty(OS, nullptr, Policy);
+ OS << ")";
+}
+
void OMPClausePrinter::VisitOMPDestroyClause(OMPDestroyClause *) {
OS << "destroy";
}
numLoopChildren(CollapsedNum, OMPD_target_teams_distribute_simd),
CollapsedNum);
}
+
+OMPInteropDirective *
+OMPInteropDirective::Create(const ASTContext &C, SourceLocation StartLoc,
+ SourceLocation EndLoc,
+ ArrayRef<OMPClause *> Clauses) {
+ return createDirective<OMPInteropDirective>(
+ C, Clauses, /*AssociatedStmt=*/nullptr, /*NumChildren=*/0, StartLoc,
+ EndLoc);
+}
+
+OMPInteropDirective *OMPInteropDirective::CreateEmpty(const ASTContext &C,
+ unsigned NumClauses,
+ EmptyShell) {
+ return createEmptyDirective<OMPInteropDirective>(C, NumClauses);
+}
PrintOMPExecutableDirective(Node);
}
+void StmtPrinter::VisitOMPInteropDirective(OMPInteropDirective *Node) {
+ Indent() << "#pragma omp interop";
+ PrintOMPExecutableDirective(Node);
+}
+
//===----------------------------------------------------------------------===//
// Expr printing methods.
//===----------------------------------------------------------------------===//
void OMPClauseProfiler::VisitOMPNogroupClause(const OMPNogroupClause *) {}
+void OMPClauseProfiler::VisitOMPInitClause(const OMPInitClause *C) {
+ VisitOMPClauseList(C);
+}
+
void OMPClauseProfiler::VisitOMPDestroyClause(const OMPDestroyClause *) {}
template<typename T>
VisitOMPLoopDirective(S);
}
+void StmtProfiler::VisitOMPInteropDirective(const OMPInteropDirective *S) {
+ VisitOMPExecutableDirective(S);
+}
+
void StmtProfiler::VisitExpr(const Expr *S) {
VisitStmt(S);
}
EmitOMPTargetTeamsDistributeSimdDirective(
cast<OMPTargetTeamsDistributeSimdDirective>(*S));
break;
+ case Stmt::OMPInteropDirectiveClass:
+ llvm_unreachable("Interop directive not supported yet.");
+ break;
}
}
case OMPD_target_enter_data:
case OMPD_target_exit_data:
case OMPD_target_update:
+ case OMPD_interop:
if ((StmtCtx & ParsedStmtContext::AllowStandaloneOpenMPDirectives) ==
ParsedStmtContext()) {
Diag(Tok, diag::err_omp_immediate_directive)
case OMPC_uses_allocators:
Clause = ParseOpenMPUsesAllocatorClause(DKind);
break;
+ case OMPC_init:
+ Clause = ParseOpenMPInteropClause(CKind, WrongDirective);
+ break;
case OMPC_device_type:
case OMPC_unknown:
skipUntilPragmaOpenMPEnd(DKind);
return Actions.ActOnOpenMPSingleExprClause(Kind, Val.get(), Loc, LLoc, RLoc);
}
+/// Parsing of OpenMP clauses that use an interop-var.
+///
+/// init-clause:
+/// init([interop-modifier, ]interop-type[[, interop-type] ... ]:interop-var)
+///
+/// destroy-clause:
+/// destroy(interop-var)
+///
+/// use-clause:
+/// use(interop-var)
+///
+/// interop-modifier:
+/// prefer_type(preference-list)
+///
+/// preference-list:
+/// foreign-runtime-id [, foreign-runtime-id]...
+///
+/// foreign-runtime-id:
+/// <string-literal> | <constant-integral-expression>
+///
+/// interop-type:
+/// target | targetsync
+///
+OMPClause *Parser::ParseOpenMPInteropClause(OpenMPClauseKind Kind,
+ bool ParseOnly) {
+ SourceLocation Loc = ConsumeToken();
+ // Parse '('.
+ BalancedDelimiterTracker T(*this, tok::l_paren, tok::annot_pragma_openmp_end);
+ if (T.expectAndConsume(diag::err_expected_lparen_after,
+ getOpenMPClauseName(Kind).data()))
+ return nullptr;
+
+ bool IsTarget = false;
+ bool IsTargetSync = false;
+ SmallVector<Expr *, 4> Prefs;
+
+ if (Kind == OMPC_init) {
+
+ // Parse optional interop-modifier.
+ if (Tok.is(tok::identifier) && PP.getSpelling(Tok) == "prefer_type") {
+ ConsumeToken();
+ BalancedDelimiterTracker PT(*this, tok::l_paren,
+ tok::annot_pragma_openmp_end);
+ if (PT.expectAndConsume(diag::err_expected_lparen_after, "prefer_type"))
+ return nullptr;
+
+ while (Tok.isNot(tok::r_paren)) {
+ SourceLocation Loc = Tok.getLocation();
+ ExprResult LHS = ParseCastExpression(AnyCastExpr);
+ ExprResult PTExpr = Actions.CorrectDelayedTyposInExpr(
+ ParseRHSOfBinaryExpression(LHS, prec::Conditional));
+ PTExpr = Actions.ActOnFinishFullExpr(PTExpr.get(), Loc,
+ /*DiscardedValue=*/false);
+ if (PTExpr.isUsable())
+ Prefs.push_back(PTExpr.get());
+ else
+ SkipUntil(tok::comma, tok::r_paren, tok::annot_pragma_openmp_end,
+ StopBeforeMatch);
+
+ if (Tok.is(tok::comma))
+ ConsumeToken();
+ }
+ PT.consumeClose();
+ }
+
+ if (!Prefs.empty()) {
+ if (Tok.is(tok::comma))
+ ConsumeToken();
+ else
+ Diag(Tok, diag::err_omp_expected_punc_after_interop_mod);
+ }
+
+ // 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 (!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.
+ SourceLocation VarLoc = Tok.getLocation();
+ ExprResult InteropVarExpr =
+ Actions.CorrectDelayedTyposInExpr(ParseAssignmentExpression());
+ if (!InteropVarExpr.isUsable()) {
+ SkipUntil(tok::comma, tok::r_paren, tok::annot_pragma_openmp_end,
+ StopBeforeMatch);
+ }
+
+ // Parse ')'.
+ SourceLocation RLoc = Tok.getLocation();
+ if (!T.consumeClose())
+ RLoc = T.getCloseLocation();
+
+ if (ParseOnly || !InteropVarExpr.isUsable() ||
+ (Kind == OMPC_init && !IsTarget && !IsTargetSync))
+ return nullptr;
+
+ if (Kind == OMPC_init)
+ return Actions.ActOnOpenMPInitClause(InteropVarExpr.get(), Prefs, IsTarget,
+ IsTargetSync, Loc, T.getOpenLocation(),
+ VarLoc, RLoc);
+
+ llvm_unreachable("Unexpected interop variable clause.");
+}
+
/// Parsing of simple OpenMP clauses like 'default' or 'proc_bind'.
///
/// default-clause:
case Stmt::OMPTeamsDistributeParallelForDirectiveClass:
case Stmt::OMPTeamsDistributeParallelForSimdDirectiveClass:
case Stmt::OMPTeamsDistributeSimdDirectiveClass:
+ case Stmt::OMPInteropDirectiveClass:
case Stmt::ReturnStmtClass:
case Stmt::SEHExceptStmtClass:
case Stmt::SEHFinallyStmtClass:
if (LangOpts.OpenMP >= 50)
AllowedNameModifiers.push_back(OMPD_simd);
break;
+ case OMPD_interop:
+ assert(AStmt == nullptr &&
+ "No associated statement allowed for 'omp interop' directive");
+ Res = ActOnOpenMPInteropDirective(ClausesWithImplicit, StartLoc, EndLoc);
+ break;
case OMPD_declare_target:
case OMPD_end_declare_target:
case OMPD_threadprivate:
CaptureRegion = OMPD_task;
break;
case OMPD_target_data:
+ case OMPD_interop:
// Do not capture device-clause expressions.
break;
case OMPD_teams_distribute_parallel_for:
return new (Context) OMPDestroyClause(StartLoc, EndLoc);
}
+StmtResult Sema::ActOnOpenMPInteropDirective(ArrayRef<OMPClause *> Clauses,
+ SourceLocation StartLoc,
+ SourceLocation EndLoc) {
+
+ // OpenMP 5.1 [2.15.1, interop Construct, Restrictions]
+ // At least one action-clause must appear on a directive.
+ // TODO: also add 'use' and 'destroy' here.
+ if (!hasClauses(Clauses, OMPC_init, OMPC_nowait)) {
+ StringRef Expected = "'init', 'use', 'destroy', or 'nowait'";
+ Diag(StartLoc, diag::err_omp_no_clause_for_directive)
+ << Expected << getOpenMPDirectiveName(OMPD_interop);
+ return StmtError();
+ }
+
+ // OpenMP 5.1 [2.15.1, interop Construct, Restrictions]
+ // A depend clause can only appear on the directive if a targetsync
+ // interop-type is present or the interop-var was initialized with
+ // the targetsync interop-type.
+
+ // If there is any 'init' clause diagnose if there is no 'init' clause with
+ // interop-type of 'targetsync'. Cases involving other directives cannot be
+ // diagnosed.
+ const OMPDependClause *DependClause = nullptr;
+ bool IsTargetSync = false;
+ for (const OMPClause *C : Clauses) {
+ if (IsTargetSync)
+ break;
+ if (const auto *InitClause = dyn_cast<OMPInitClause>(C))
+ IsTargetSync = InitClause->getIsTargetSync();
+ else if (const auto *DC = dyn_cast<OMPDependClause>(C))
+ DependClause = DC;
+ }
+ if (DependClause && !IsTargetSync) {
+ Diag(DependClause->getBeginLoc(), diag::err_omp_interop_bad_depend_clause);
+ return StmtError();
+ }
+
+ // OpenMP 5.1 [2.15.1, interop Construct, Restrictions]
+ // Each interop-var may be specified for at most one action-clause of each
+ // interop construct.
+ llvm::SmallPtrSet<const VarDecl *, 4> InteropVars;
+ for (const OMPClause *C : Clauses) {
+ OpenMPClauseKind ClauseKind = C->getClauseKind();
+ const DeclRefExpr *DRE = nullptr;
+ SourceLocation VarLoc;
+
+ if (ClauseKind == OMPC_init) {
+ const auto *IC = cast<OMPInitClause>(C);
+ VarLoc = IC->getVarLoc();
+ DRE = dyn_cast_or_null<DeclRefExpr>(IC->getInteropVar());
+ }
+ // TODO: 'use' and 'destroy' clauses to be added here.
+
+ if (!DRE)
+ continue;
+
+ if (const auto *VD = dyn_cast<VarDecl>(DRE->getDecl())) {
+ if (!InteropVars.insert(VD->getCanonicalDecl()).second) {
+ Diag(VarLoc, diag::err_omp_interop_var_multiple_actions) << VD;
+ return StmtError();
+ }
+ }
+ }
+
+ return OMPInteropDirective::Create(Context, StartLoc, EndLoc, Clauses);
+}
+
+static bool isValidInteropVariable(Sema &SemaRef, Expr *InteropVarExpr,
+ SourceLocation VarLoc,
+ OpenMPClauseKind Kind) {
+ if (InteropVarExpr->isValueDependent() || InteropVarExpr->isTypeDependent() ||
+ InteropVarExpr->isInstantiationDependent() ||
+ InteropVarExpr->containsUnexpandedParameterPack())
+ return true;
+
+ const auto *DRE = dyn_cast<DeclRefExpr>(InteropVarExpr);
+ if (!DRE || !isa<VarDecl>(DRE->getDecl())) {
+ SemaRef.Diag(VarLoc, diag::err_omp_interop_variable_expected) << 0;
+ return false;
+ }
+
+ // Interop variable should be of type omp_interop_t.
+ bool HasError = false;
+ QualType InteropType;
+ LookupResult Result(SemaRef, &SemaRef.Context.Idents.get("omp_interop_t"),
+ VarLoc, Sema::LookupOrdinaryName);
+ if (SemaRef.LookupName(Result, SemaRef.getCurScope())) {
+ NamedDecl *ND = Result.getFoundDecl();
+ if (const auto *TD = dyn_cast<TypeDecl>(ND)) {
+ InteropType = QualType(TD->getTypeForDecl(), 0);
+ } else {
+ HasError = true;
+ }
+ } else {
+ HasError = true;
+ }
+
+ if (HasError) {
+ SemaRef.Diag(VarLoc, diag::err_omp_implied_type_not_found)
+ << "omp_interop_t";
+ return false;
+ }
+
+ QualType VarType = InteropVarExpr->getType().getUnqualifiedType();
+ if (!SemaRef.Context.hasSameType(InteropType, VarType)) {
+ SemaRef.Diag(VarLoc, diag::err_omp_interop_variable_wrong_type);
+ return false;
+ }
+
+ // OpenMP 5.1 [2.15.1, interop Construct, Restrictions]
+ // The interop-var passed to init or destroy must be non-const.
+ // TODO: 'destroy' clause too.
+ if (Kind == OMPC_init &&
+ isConstNotMutableType(SemaRef, InteropVarExpr->getType())) {
+ SemaRef.Diag(VarLoc, diag::err_omp_interop_variable_expected)
+ << /*non-const*/ 1;
+ return false;
+ }
+ return true;
+}
+
+OMPClause *
+Sema::ActOnOpenMPInitClause(Expr *InteropVar, ArrayRef<Expr *> PrefExprs,
+ bool IsTarget, bool IsTargetSync,
+ SourceLocation StartLoc, SourceLocation LParenLoc,
+ SourceLocation VarLoc, SourceLocation EndLoc) {
+
+ if (!isValidInteropVariable(*this, InteropVar, VarLoc, OMPC_init))
+ return nullptr;
+
+ // Check prefer_type values. These foreign-runtime-id values are either
+ // string literals or constant integral expressions.
+ for (const Expr *E : PrefExprs) {
+ if (E->isValueDependent() || E->isTypeDependent() ||
+ E->isInstantiationDependent() || E->containsUnexpandedParameterPack())
+ continue;
+ if (E->isIntegerConstantExpr(Context))
+ continue;
+ if (isa<StringLiteral>(E))
+ continue;
+ Diag(E->getExprLoc(), diag::err_omp_interop_prefer_type);
+ return nullptr;
+ }
+
+ return OMPInitClause::Create(Context, InteropVar, PrefExprs, IsTarget,
+ IsTargetSync, StartLoc, LParenLoc, VarLoc,
+ EndLoc);
+}
+
OMPClause *Sema::ActOnOpenMPVarListClause(
OpenMPClauseKind Kind, ArrayRef<Expr *> VarList, Expr *DepModOrTailExpr,
const OMPVarListLocTy &Locs, SourceLocation ColonLoc,
LParenLoc, EndLoc);
}
+ /// Build a new OpenMP 'init' clause.
+ ///
+ /// By default, performs semantic analysis to build the new OpenMP clause.
+ /// Subclasses may override this routine to provide different behavior.
+ OMPClause *RebuildOMPInitClause(Expr *InteropVar, ArrayRef<Expr *> PrefExprs,
+ bool IsTarget, bool IsTargetSync,
+ SourceLocation StartLoc,
+ SourceLocation LParenLoc,
+ SourceLocation VarLoc,
+ SourceLocation EndLoc) {
+ return getSema().ActOnOpenMPInitClause(InteropVar, PrefExprs, IsTarget,
+ IsTargetSync, StartLoc, LParenLoc,
+ VarLoc, EndLoc);
+ }
+
/// Rebuild the operand to an Objective-C \@synchronized statement.
///
/// By default, performs semantic analysis to build the new statement.
return Res;
}
+template <typename Derived>
+StmtResult
+TreeTransform<Derived>::TransformOMPInteropDirective(OMPInteropDirective *D) {
+ DeclarationNameInfo DirName;
+ getDerived().getSema().StartOpenMPDSABlock(OMPD_interop, DirName, nullptr,
+ D->getBeginLoc());
+ StmtResult Res = getDerived().TransformOMPExecutableDirective(D);
+ getDerived().getSema().EndOpenMPDSABlock(Res.get());
+ return Res;
+}
//===----------------------------------------------------------------------===//
// OpenMP clause transformation
}
template <typename Derived>
+OMPClause *TreeTransform<Derived>::TransformOMPInitClause(OMPInitClause *C) {
+ ExprResult IVR = getDerived().TransformExpr(C->getInteropVar());
+ if (IVR.isInvalid())
+ return nullptr;
+
+ llvm::SmallVector<Expr *, 8> PrefExprs;
+ PrefExprs.reserve(C->varlist_size() - 1);
+ for (Expr *E : llvm::drop_begin(C->varlists())) {
+ ExprResult ER = getDerived().TransformExpr(cast<Expr>(E));
+ if (ER.isInvalid())
+ return nullptr;
+ PrefExprs.push_back(ER.get());
+ }
+ return getDerived().RebuildOMPInitClause(
+ IVR.get(), PrefExprs, C->getIsTarget(), C->getIsTargetSync(),
+ C->getBeginLoc(), C->getLParenLoc(), C->getVarLoc(), C->getEndLoc());
+}
+
+template <typename Derived>
OMPClause *
TreeTransform<Derived>::TransformOMPDestroyClause(OMPDestroyClause *C) {
// No need to rebuild this clause, no template-dependent parameters.
case llvm::omp::OMPC_order:
C = new (Context) OMPOrderClause();
break;
+ case llvm::omp::OMPC_init:
+ C = OMPInitClause::CreateEmpty(Context, Record.readInt());
+ break;
case llvm::omp::OMPC_destroy:
C = new (Context) OMPDestroyClause();
break;
void OMPClauseReader::VisitOMPNogroupClause(OMPNogroupClause *) {}
+void OMPClauseReader::VisitOMPInitClause(OMPInitClause *C) {
+ unsigned NumVars = C->varlist_size();
+ SmallVector<Expr *, 16> Vars;
+ Vars.reserve(NumVars);
+ for (unsigned I = 0; I != NumVars; ++I)
+ Vars.push_back(Record.readSubExpr());
+ C->setVarRefs(Vars);
+ C->setIsTarget(Record.readBool());
+ C->setIsTargetSync(Record.readBool());
+ C->setLParenLoc(Record.readSourceLocation());
+ C->setVarLoc(Record.readSourceLocation());
+}
+
void OMPClauseReader::VisitOMPDestroyClause(OMPDestroyClause *) {}
void OMPClauseReader::VisitOMPUnifiedAddressClause(OMPUnifiedAddressClause *) {}
VisitOMPLoopDirective(D);
}
+void ASTStmtReader::VisitOMPInteropDirective(OMPInteropDirective *D) {
+ VisitStmt(D);
+ VisitOMPExecutableDirective(D);
+}
+
//===----------------------------------------------------------------------===//
// ASTReader Implementation
//===----------------------------------------------------------------------===//
break;
}
+ case STMT_OMP_INTEROP_DIRECTIVE:
+ S = OMPInteropDirective::CreateEmpty(
+ Context, Record[ASTStmtReader::NumStmtFields], Empty);
+ break;
+
case EXPR_CXX_OPERATOR_CALL:
S = CXXOperatorCallExpr::CreateEmpty(
Context, /*NumArgs=*/Record[ASTStmtReader::NumExprFields],
void OMPClauseWriter::VisitOMPNogroupClause(OMPNogroupClause *) {}
+void OMPClauseWriter::VisitOMPInitClause(OMPInitClause *C) {
+ Record.push_back(C->varlist_size());
+ for (Expr *VE : C->varlists())
+ Record.AddStmt(VE);
+ Record.writeBool(C->getIsTarget());
+ Record.writeBool(C->getIsTargetSync());
+ Record.AddSourceLocation(C->getLParenLoc());
+ Record.AddSourceLocation(C->getVarLoc());
+}
+
void OMPClauseWriter::VisitOMPDestroyClause(OMPDestroyClause *) {}
void OMPClauseWriter::VisitOMPPrivateClause(OMPPrivateClause *C) {
Code = serialization::STMT_OMP_TARGET_TEAMS_DISTRIBUTE_SIMD_DIRECTIVE;
}
+void ASTStmtWriter::VisitOMPInteropDirective(OMPInteropDirective *D) {
+ VisitStmt(D);
+ VisitOMPExecutableDirective(D);
+ Code = serialization::STMT_OMP_INTEROP_DIRECTIVE;
+}
+
//===----------------------------------------------------------------------===//
// ASTWriter Implementation
//===----------------------------------------------------------------------===//
case Stmt::OMPTargetTeamsDistributeParallelForSimdDirectiveClass:
case Stmt::OMPTargetTeamsDistributeSimdDirectiveClass:
case Stmt::OMPTileDirectiveClass:
+ case Stmt::OMPInteropDirectiveClass:
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-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
+
+typedef void *omp_interop_t;
+
+//PRINT-LABEL: void foo1(
+//DUMP-LABEL: FunctionDecl {{.*}} foo1
+void foo1(int *ap, int dev) {
+ omp_interop_t I;
+ omp_interop_t &IRef = I;
+
+ //PRINT: #pragma omp interop init(target : I)
+ //DUMP: OMPInteropDirective
+ //DUMP: OMPInitClause
+ //DUMP: DeclRefExpr{{.*}}'omp_interop_t'{{.*}}Var{{.*}}'I'
+ #pragma omp interop init(target:I)
+
+ //PRINT: #pragma omp interop init(target : IRef)
+ //DUMP: OMPInteropDirective
+ //DUMP: OMPInitClause
+ //DUMP: DeclRefExpr{{.*}}'omp_interop_t'{{.*}}Var{{.*}}'IRef'
+ #pragma omp interop init(target:IRef)
+
+ //PRINT: #pragma omp interop device(dev) depend(inout : ap) init(targetsync : I)
+ //DUMP: OMPInteropDirective
+ //DUMP: OMPDeviceClause
+ //DUMP: DeclRefExpr{{.*}}'dev' 'int'
+ //DUMP: OMPDependClause
+ //DUMP: DeclRefExpr{{.*}}'ap' 'int *'
+ //DUMP: OMPInitClause
+ //DUMP: DeclRefExpr{{.*}}'omp_interop_t'{{.*}}Var{{.*}}'I'
+ #pragma omp interop device(dev) depend(inout:ap) init(targetsync:I)
+
+ //PRINT: #pragma omp interop init(prefer_type(1,2,3,4,5,6), targetsync : I)
+ //DUMP: OMPInteropDirective
+ //DUMP: OMPInitClause
+ //DUMP: DeclRefExpr{{.*}}'omp_interop_t'{{.*}}Var{{.*}}'I'
+ //DUMP: IntegerLiteral{{.*}}1
+ //DUMP: IntegerLiteral{{.*}}2
+ //DUMP: IntegerLiteral{{.*}}3
+ //DUMP: IntegerLiteral{{.*}}4
+ //DUMP: IntegerLiteral{{.*}}5
+ //DUMP: IntegerLiteral{{.*}}6
+ #pragma omp interop init(prefer_type(1,2,3,4,5,6),targetsync:I)
+
+ //PRINT: #pragma omp interop init(prefer_type(2,4,6,1), targetsync : I)
+ //DUMP: OMPInteropDirective
+ //DUMP: OMPInitClause
+ //DUMP: DeclRefExpr{{.*}}'omp_interop_t'{{.*}}Var{{.*}}'I'
+ //DUMP: IntegerLiteral{{.*}}2
+ //DUMP: IntegerLiteral{{.*}}4
+ //DUMP: IntegerLiteral{{.*}}6
+ //DUMP: IntegerLiteral{{.*}}1
+ #pragma omp interop init(prefer_type(2,4,6,1),targetsync:I)
+
+ //PRINT: #pragma omp interop init(prefer_type("cuda","cuda_driver","opencl","sycl","hip","level_zero"), targetsync : I)
+ //DUMP: OMPInteropDirective
+ //DUMP: OMPInitClause
+ //DUMP: DeclRefExpr{{.*}}'omp_interop_t'{{.*}}Var{{.*}}'I'
+ //DUMP: StringLiteral{{.*}}"cuda"
+ //DUMP: StringLiteral{{.*}}"cuda_driver"
+ //DUMP: StringLiteral{{.*}}"opencl"
+ //DUMP: StringLiteral{{.*}}"sycl"
+ //DUMP: StringLiteral{{.*}}"hip"
+ //DUMP: StringLiteral{{.*}}"level_zero"
+ #pragma omp interop init( \
+ prefer_type("cuda","cuda_driver","opencl","sycl","hip","level_zero"), \
+ targetsync:I)
+
+ //PRINT: #pragma omp interop init(prefer_type("level_zero",2,4), targetsync : I)
+ //DUMP: OMPInteropDirective
+ //DUMP: OMPInitClause
+ //DUMP: DeclRefExpr{{.*}}'omp_interop_t'{{.*}}Var{{.*}}'I'
+ //DUMP: StringLiteral{{.*}}"level_zero"
+ //DUMP: IntegerLiteral{{.*}}2
+ //DUMP: IntegerLiteral{{.*}}4
+ #pragma omp interop init(prefer_type("level_zero",2,4),targetsync:I)
+
+ omp_interop_t J;
+
+ //PRINT: #pragma omp interop init(target : I) init(targetsync : J)
+ //DUMP: OMPInteropDirective
+ //DUMP: OMPInitClause
+ //DUMP: DeclRefExpr{{.*}}'omp_interop_t'{{.*}}Var{{.*}}'I'
+ //DUMP: OMPInitClause
+ //DUMP: DeclRefExpr{{.*}}'omp_interop_t'{{.*}}Var{{.*}}'J'
+ #pragma omp interop init(target:I) init(targetsync:J)
+
+}
+
+//DUMP: FunctionTemplateDecl{{.*}}fooTemp
+//DUMP-NEXT: NonTypeTemplateParmDecl{{.*}}'int{{.*}}I
+template <int I>
+void fooTemp() {
+ omp_interop_t interop_var;
+ //PRINT: #pragma omp interop init(prefer_type(I,4,"level_one"), target : interop_var)
+ //DUMP: FunctionDecl{{.*}}fooTemp
+ //DUMP: OMPInteropDirective
+ //DUMP: OMPInitClause
+ //DUMP: DeclRefExpr{{.*}}'omp_interop_t'{{.*}}'interop_var'
+ //DUMP: DeclRefExpr{{.*}}NonTypeTemplateParm{{.*}}'I' 'int'
+ //DUMP: IntegerLiteral{{.*}}'int' 4
+ //DUMP: StringLiteral{{.*}}"level_one"
+
+ //PRINT: #pragma omp interop init(prefer_type(3,4,"level_one"), target : interop_var)
+ //DUMP: FunctionDecl{{.*}}fooTemp
+ //DUMP: TemplateArgument integral 3
+ //DUMP: OMPInteropDirective
+ //DUMP: OMPInitClause
+ //DUMP: DeclRefExpr{{.*}}'omp_interop_t'{{.*}}'interop_var'
+ //DUMP: SubstNonTypeTemplateParmExpr{{.*}}'int'
+ //DUMP: NonTypeTemplateParmDecl{{.*}}'int'{{.*}}I
+ //DUMP: IntegerLiteral{{.*}}'int' 3
+ //DUMP: IntegerLiteral{{.*}}'int' 4
+ //DUMP: StringLiteral{{.*}}"level_one"
+ #pragma omp interop init(prefer_type(I,4,"level_one"), target: interop_var)
+}
+
+//DUMP: FunctionTemplateDecl{{.*}}barTemp
+//DUMP-NEXT: TemplateTypeParmDecl{{.*}}typename{{.*}}T
+template <typename T>
+void barTemp(T t) {
+ //PRINT: #pragma omp interop init(prefer_type(4,"level_one"), target : t)
+ //DUMP: FunctionDecl{{.*}}barTemp 'void (T)'
+ //DUMP: ParmVarDecl{{.*}}t 'T'
+ //DUMP: OMPInteropDirective
+ //DUMP: OMPInitClause
+ //DUMP: DeclRefExpr{{.*}}ParmVar{{.*}}'t' 'T'
+ //DUMP: IntegerLiteral{{.*}}'int' 4
+ //DUMP: StringLiteral{{.*}}"level_one"
+ #pragma omp interop init(prefer_type(4,"level_one"), target: t)
+
+ //DUMP: FunctionDecl{{.*}}barTemp 'void (void *)'
+ //DUMP: TemplateArgument type 'void *'
+ //DUMP: ParmVarDecl{{.*}}t 'void *'
+ //DUMP: OMPInteropDirective
+ //DUMP: OMPInitClause
+ //DUMP: DeclRefExpr{{.*}}ParmVar{{.*}}'t' 'void *'
+ //PRINT: #pragma omp interop init(prefer_type(4,"level_one"), target : t)
+}
+
+void bar()
+{
+ fooTemp<3>();
+ omp_interop_t Ivar;
+ barTemp(Ivar);
+}
+
+#endif // HEADER
--- /dev/null
+// RUN: %clang_cc1 -verify -fopenmp -std=c++11 -o - -DWITHDEF %s
+// RUN: %clang_cc1 -verify -fopenmp -std=c++11 -o - -DWITHOUTDEF %s
+
+#ifdef WITHDEF
+typedef void *omp_interop_t;
+
+void foo(int *Ap) {
+ omp_interop_t InteropVar;
+ omp_interop_t Another;
+
+ //expected-error@+1 {{expected interop type: 'target' and/or 'targetsync'}}
+ #pragma omp interop init(target,foo:InteropVar) init(target:Another)
+
+ //expected-error@+1 {{use of undeclared identifier 'NoDeclVar'}}
+ #pragma omp interop init(target:NoDeclVar) init(target:Another)
+
+ //expected-error@+2 {{expected interop type: 'target' and/or 'targetsync'}}
+ //expected-error@+1 {{expected expression}}
+ #pragma omp interop init(InteropVar) init(target:Another)
+
+ //expected-warning@+1 {{missing ':' after interop types}}
+ #pragma omp interop init(target InteropVar)
+
+ //expected-error@+1 {{expected expression}}
+ #pragma omp interop init(prefer_type(1,+,3),target:InteropVar) \
+ init(target:Another)
+
+ int IntVar;
+ struct S { int I; } SVar;
+
+ //expected-error@+1 {{interop variable must be of type 'omp_interop_t'}}
+ #pragma omp interop init(prefer_type(1,"sycl",3),target:IntVar) \
+ init(target:Another)
+
+ //expected-error@+1 {{interop variable must be of type 'omp_interop_t'}}
+ #pragma omp interop init(prefer_type(1,"sycl",3),target:SVar) \
+ init(target:Another)
+
+ int a, b;
+ //expected-error@+1 {{expected variable of type 'omp_interop_t'}}
+ #pragma omp interop init(target:a+b) init(target:Another)
+
+ const omp_interop_t C = (omp_interop_t)5;
+ //expected-error@+1 {{expected non-const variable of type 'omp_interop_t'}}
+ #pragma omp interop init(target:C) init(target:Another)
+
+ //expected-error@+1 {{prefer_list item must be a string literal or constant integral expression}}
+ #pragma omp interop init(prefer_type(1.0),target:InteropVar) \
+ init(target:Another)
+
+ //expected-error@+1 {{prefer_list item must be a string literal or constant integral expression}}
+ #pragma omp interop init(prefer_type(a),target:InteropVar) \
+ init(target:Another)
+
+ //expected-error@+1 {{expected at least one 'init', 'use', 'destroy', or 'nowait' clause for '#pragma omp interop'}}
+ #pragma omp interop device(0)
+
+ //expected-warning@+1 {{interop type 'target' cannot be specified more than once}}
+ #pragma omp interop init(target,targetsync,target:InteropVar)
+
+ //expected-error@+1 {{'depend' clause requires the 'targetsync' interop type}}
+ #pragma omp interop init(target:InteropVar) depend(inout:Ap)
+
+ //expected-error@+1 {{interop variable 'InteropVar' used in multiple action clauses}}
+ #pragma omp interop init(target:InteropVar) init(target:InteropVar)
+
+ //expected-error@+1 {{directive '#pragma omp interop' cannot contain more than one 'device' clause}}
+ #pragma omp interop init(target:InteropVar) device(0) device(1)
+
+ //expected-error@+1 {{argument to 'device' clause must be a non-negative integer value}}
+ #pragma omp interop init(target:InteropVar) device(-4)
+
+ //expected-error@+1 {{directive '#pragma omp interop' cannot contain more than one 'nowait' clause}}
+ #pragma omp interop nowait init(target:InteropVar) nowait
+}
+#endif
+#ifdef WITHOUTDEF
+void foo() {
+ int InteropVar;
+ //expected-error@+1 {{'omp_interop_t' type not found; include <omp.h>}}
+ #pragma omp interop init(prefer_type(1,"sycl",3),target:InteropVar) nowait
+}
+#endif
foo();
}
-#pragma omp taskgroup init // expected-warning {{extra tokens at the end of '#pragma omp taskgroup' are ignored}}
+#pragma omp taskgroup initi // expected-warning {{extra tokens at the end of '#pragma omp taskgroup' are ignored}}
;
return 0;
}
void OMPClauseEnqueue::VisitOMPNogroupClause(const OMPNogroupClause *) {}
+void OMPClauseEnqueue::VisitOMPInitClause(const OMPInitClause *C) {
+ VisitOMPClauseList(C);
+}
+
void OMPClauseEnqueue::VisitOMPDestroyClause(const OMPDestroyClause *) {}
void OMPClauseEnqueue::VisitOMPUnifiedAddressClause(
"OMPTargetTeamsDistributeParallelForSimdDirective");
case CXCursor_OMPTargetTeamsDistributeSimdDirective:
return cxstring::createRef("OMPTargetTeamsDistributeSimdDirective");
+ case CXCursor_OMPInteropDirective:
+ return cxstring::createRef("OMPInteropDirective");
case CXCursor_OverloadCandidate:
return cxstring::createRef("OverloadCandidate");
case CXCursor_TypeAliasTemplateDecl:
case Stmt::OMPTargetTeamsDistributeSimdDirectiveClass:
K = CXCursor_OMPTargetTeamsDistributeSimdDirective;
break;
+ case Stmt::OMPInteropDirectiveClass:
+ K = CXCursor_OMPInteropDirective;
+ break;
case Stmt::BuiltinBitCastExprClass:
K = CXCursor_BuiltinBitCastExpr;
}
CHECK_SIMPLE_CLAUSE(Update, OMPC_update)
CHECK_SIMPLE_CLAUSE(UseDeviceAddr, OMPC_use_device_addr)
CHECK_SIMPLE_CLAUSE(Write, OMPC_write)
+CHECK_SIMPLE_CLAUSE(Init, OMPC_init)
CHECK_REQ_SCALAR_INT_CLAUSE(Allocator, OMPC_allocator)
CHECK_REQ_SCALAR_INT_CLAUSE(Grainsize, OMPC_grainsize)
OMP_ORDER_concurrent
];
}
+def OMPC_Init : Clause<"init"> {
+ let clangClass = "OMPInitClause";
+}
def OMPC_Destroy : Clause<"destroy"> {
let clangClass = "OMPDestroyClause";
}
VersionedClause<OMPC_NoWait>
];
}
+def OMP_interop : Directive<"interop"> {
+ let allowedClauses = [
+ VersionedClause<OMPC_Device>,
+ VersionedClause<OMPC_Depend>,
+ VersionedClause<OMPC_Init>,
+ VersionedClause<OMPC_NoWait>,
+ ];
+}
def OMP_Unknown : Directive<"unknown"> {
let isDefault = true;
}