Author: Zahira Ammarguellat Date: 2026-01-15T09:48:24-05:00 New Revision: bde808bf1ccf4ba95011a08468c23d4cdfc5573c
URL: https://github.com/llvm/llvm-project/commit/bde808bf1ccf4ba95011a08468c23d4cdfc5573c DIFF: https://github.com/llvm/llvm-project/commit/bde808bf1ccf4ba95011a08468c23d4cdfc5573c.diff LOG: [CLANG][OpenMP] Add support for OpenMP6.0 transparent clause. (#174646) Add basic parsing and semantic support for transparent clause for task andtaskloop directives described in Section 17.9.6 of https://www.openmp.org/wp-content/uploads/OpenMP-API-Specification-6-0.pdf . Added: clang/test/OpenMP/task_transparent_messages.cpp clang/test/OpenMP/task_transparent_serialization.cpp Modified: clang/docs/OpenMPSupport.rst clang/docs/ReleaseNotes.rst clang/include/clang/AST/OpenMPClause.h clang/include/clang/AST/RecursiveASTVisitor.h clang/include/clang/Basic/DiagnosticSemaKinds.td clang/include/clang/Basic/OpenMPKinds.def clang/include/clang/Sema/SemaOpenMP.h clang/lib/AST/OpenMPClause.cpp clang/lib/AST/StmtProfile.cpp clang/lib/CodeGen/CGOpenMPRuntime.cpp clang/lib/Parse/ParseOpenMP.cpp clang/lib/Sema/SemaOpenMP.cpp clang/lib/Sema/TreeTransform.h clang/lib/Serialization/ASTReader.cpp clang/lib/Serialization/ASTWriter.cpp clang/test/OpenMP/task_ast_print.cpp clang/test/OpenMP/task_codegen.cpp clang/test/OpenMP/taskloop_ast_print.cpp clang/test/OpenMP/taskloop_codegen.cpp clang/tools/libclang/CIndex.cpp llvm/include/llvm/Frontend/OpenMP/ClauseT.h llvm/include/llvm/Frontend/OpenMP/OMP.td Removed: ################################################################################ diff --git a/clang/docs/OpenMPSupport.rst b/clang/docs/OpenMPSupport.rst index 7941c2e439ed6..c32dff82d9972 100644 --- a/clang/docs/OpenMPSupport.rst +++ b/clang/docs/OpenMPSupport.rst @@ -492,7 +492,7 @@ implementation. +-------------------------------------------------------------+---------------------------+---------------------------+--------------------------------------------------------------------------+ | memscope clause for atomic and flush | :none:`unclaimed` | :none:`unclaimed` | | +-------------------------------------------------------------+---------------------------+---------------------------+--------------------------------------------------------------------------+ -| transparent clause (hull tasks) | :none:`unclaimed` | :none:`unclaimed` | | +| transparent clause (hull tasks) | :part:`partial` | :none:`unclaimed` | Clang parsing/sema https://github.com/llvm/llvm-project/pull/166810 | +-------------------------------------------------------------+---------------------------+---------------------------+--------------------------------------------------------------------------+ | rule-based compound directives | :part:`In Progress` | :part:`In Progress` | kparzysz | | | | | Testing for Fortran missing | diff --git a/clang/docs/ReleaseNotes.rst b/clang/docs/ReleaseNotes.rst index 4139d1d80ed4a..64d2e256547fe 100644 --- a/clang/docs/ReleaseNotes.rst +++ b/clang/docs/ReleaseNotes.rst @@ -235,6 +235,7 @@ Python Binding Changes OpenMP Support -------------- +- Added support for ``transparent`` clause in task and taskloop directives. Improvements ^^^^^^^^^^^^ diff --git a/clang/include/clang/AST/OpenMPClause.h b/clang/include/clang/AST/OpenMPClause.h index 6525e64ff102f..2ef363952f67f 100644 --- a/clang/include/clang/AST/OpenMPClause.h +++ b/clang/include/clang/AST/OpenMPClause.h @@ -1495,6 +1495,78 @@ class OMPThreadsetClause final : public OMPClause { } }; +/// This class represents the 'transparent' clause in the '#pragma omp task' +/// directive. +/// +/// \code +/// #pragma omp task transparent(omp_not_impex) +/// \endcode +/// +/// In this example, the directive '#pragma omp task' has a 'transparent' +/// clause with OpenMP keyword 'omp_not_impex`. Other valid keywords that may +/// appear in this clause are 'omp_import', 'omp_export' and 'omp_impex'. +/// +class OMPTransparentClause final : public OMPClause { + friend class OMPClauseReader; + + /// Location of '('. + SourceLocation LParenLoc; + + /// Argument of the 'transparent' clause. + Expr *ImpexType = nullptr; + + /// Sets the location of '('. + void setLParenLoc(SourceLocation Loc) { LParenLoc = Loc; } + + void setImpexTypeKind(Expr *E) { ImpexType = E; } + +public: + /// Build 'transparent' clause with argument \a A ('omp_not_impex', + /// 'omp_import', 'omp_export' or 'omp_impex') + /// + /// \param A Argument of the clause ('omp_not_impex', 'omp_import', + /// 'omp_export' or 'omp_impex') + /// \param ALoc Starting location of the argument. + /// \param StartLoc Starting location of the clause. + /// \param LParenLoc Location of '('. + /// \param EndLoc Ending location of the clause. + OMPTransparentClause(Expr *ImpexTypeKind, SourceLocation StartLoc, + SourceLocation LParenLoc, SourceLocation EndLoc) + : OMPClause(llvm::omp::OMPC_transparent, StartLoc, EndLoc), + LParenLoc(LParenLoc), ImpexType(ImpexTypeKind) {} + + /// Build an empty clause. + OMPTransparentClause() + : OMPClause(llvm::omp::OMPC_transparent, SourceLocation(), + SourceLocation()) {} + + /// Returns the location of '('. + SourceLocation getLParenLoc() const { return LParenLoc; } + + /// Returns argument of the clause. + Expr *getImpexType() const { return ImpexType; } + + child_range children() { + return child_range(reinterpret_cast<Stmt **>(&ImpexType), + reinterpret_cast<Stmt **>(&ImpexType) + 1); + } + + const_child_range children() const { + return const_cast<OMPTransparentClause *>(this)->children(); + } + + 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()); + } + + static bool classof(const OMPClause *T) { + return T->getClauseKind() == llvm::omp::OMPC_transparent; + } +}; + /// This represents 'proc_bind' clause in the '#pragma omp ...' /// directive. /// diff --git a/clang/include/clang/AST/RecursiveASTVisitor.h b/clang/include/clang/AST/RecursiveASTVisitor.h index ddec2c52fb681..c416625ad64fd 100644 --- a/clang/include/clang/AST/RecursiveASTVisitor.h +++ b/clang/include/clang/AST/RecursiveASTVisitor.h @@ -3531,6 +3531,13 @@ bool RecursiveASTVisitor<Derived>::VisitOMPThreadsetClause( return true; } +template <typename Derived> +bool RecursiveASTVisitor<Derived>::VisitOMPTransparentClause( + OMPTransparentClause *C) { + TRY_TO(TraverseStmt(C->getImpexType())); + return true; +} + template <typename Derived> bool RecursiveASTVisitor<Derived>::VisitOMPProcBindClause(OMPProcBindClause *) { return true; diff --git a/clang/include/clang/Basic/DiagnosticSemaKinds.td b/clang/include/clang/Basic/DiagnosticSemaKinds.td index 5cbbc7d130c99..eb7a608f798b8 100644 --- a/clang/include/clang/Basic/DiagnosticSemaKinds.td +++ b/clang/include/clang/Basic/DiagnosticSemaKinds.td @@ -12477,6 +12477,10 @@ def err_ompx_bare_no_grid : Error< "'ompx_bare' clauses requires explicit grid size via 'num_teams' and 'thread_limit' clauses">; def err_omp_multi_expr_not_allowed: Error<"only one expression allowed in '%0' clause">; def err_ompx_more_than_three_expr_not_allowed: Error<"at most three expressions are allowed in '%0' clause in 'target teams ompx_bare' construct">; +def err_omp_transparent_invalid_value : Error<"invalid value for transparent clause," + " expected one of: omp_not_impex, omp_import, omp_export, omp_impex">; +def err_omp_transparent_invalid_type : Error< + "transparent clause cannot be applied to type: %0">; } // end of OpenMP category let CategoryName = "Related Result Type Issue" in { diff --git a/clang/include/clang/Basic/OpenMPKinds.def b/clang/include/clang/Basic/OpenMPKinds.def index ceac89d3aba6d..4f7858097a0d4 100644 --- a/clang/include/clang/Basic/OpenMPKinds.def +++ b/clang/include/clang/Basic/OpenMPKinds.def @@ -107,6 +107,9 @@ #ifndef OPENMP_THREADSET_KIND #define OPENMP_THREADSET_KIND(Name) #endif +#ifndef OPENMP_TRANSPARENT_KIND +#define OPENMP_TRANSPARENT_KIND(Name) +#endif #ifndef OPENMP_NEED_DEVICE_PTR_KIND #define OPENMP_NEED_DEVICE_PTR_KIND(Name) #endif @@ -314,4 +317,5 @@ OPENMP_NEED_DEVICE_PTR_KIND(fb_preserve) #undef OPENMP_DOACROSS_MODIFIER #undef OPENMP_ALLOCATE_MODIFIER #undef OPENMP_THREADSET_KIND +#undef OPENMP_TRANSPARENT_KIND #undef OPENMP_NEED_DEVICE_PTR_KIND diff --git a/clang/include/clang/Sema/SemaOpenMP.h b/clang/include/clang/Sema/SemaOpenMP.h index 2d05b4423140b..c932e8f9c1a52 100644 --- a/clang/include/clang/Sema/SemaOpenMP.h +++ b/clang/include/clang/Sema/SemaOpenMP.h @@ -981,6 +981,11 @@ class SemaOpenMP : public SemaBase { SourceLocation StartLoc, SourceLocation LParenLoc, SourceLocation EndLoc); + /// Called on well-formed 'transparent' clause. + OMPClause *ActOnOpenMPTransparentClause(Expr *Transparent, + SourceLocation StartLoc, + SourceLocation LParenLoc, + SourceLocation EndLoc); /// Called on well-formed 'proc_bind' clause. OMPClause *ActOnOpenMPProcBindClause(llvm::omp::ProcBindKind Kind, SourceLocation KindLoc, @@ -1472,6 +1477,13 @@ class SemaOpenMP : public SemaBase { void setOpenMPDeviceNumID(StringRef ID); + enum class OpenMPImpexType { + OMP_NotImpex = 0, + OMP_Impex = 1, + OMP_Import = 2, + OMP_Export = 3 + }; + private: void *VarDataSharingAttributesStack; diff --git a/clang/lib/AST/OpenMPClause.cpp b/clang/lib/AST/OpenMPClause.cpp index 2183d77de8fa7..fc364418ce51c 100644 --- a/clang/lib/AST/OpenMPClause.cpp +++ b/clang/lib/AST/OpenMPClause.cpp @@ -127,6 +127,7 @@ const OMPClauseWithPreInit *OMPClauseWithPreInit::get(const OMPClause *C) { case OMPC_untied: case OMPC_mergeable: case OMPC_threadset: + case OMPC_transparent: case OMPC_threadprivate: case OMPC_groupprivate: case OMPC_flush: @@ -2051,6 +2052,12 @@ void OMPClausePrinter::VisitOMPThreadsetClause(OMPThreadsetClause *Node) { << ")"; } +void OMPClausePrinter::VisitOMPTransparentClause(OMPTransparentClause *Node) { + OS << "transparent("; + Node->getImpexType()->printPretty(OS, nullptr, Policy, 0); + OS << ")"; +} + void OMPClausePrinter::VisitOMPProcBindClause(OMPProcBindClause *Node) { OS << "proc_bind(" << getOpenMPSimpleClauseTypeName(OMPC_proc_bind, diff --git a/clang/lib/AST/StmtProfile.cpp b/clang/lib/AST/StmtProfile.cpp index a626d043676e0..efabe9809c361 100644 --- a/clang/lib/AST/StmtProfile.cpp +++ b/clang/lib/AST/StmtProfile.cpp @@ -550,6 +550,12 @@ void OMPClauseProfiler::VisitOMPDefaultClause(const OMPDefaultClause *C) { } void OMPClauseProfiler::VisitOMPThreadsetClause(const OMPThreadsetClause *C) {} +void OMPClauseProfiler::VisitOMPTransparentClause( + const OMPTransparentClause *C) { + if (C->getImpexType()) + Profiler->VisitStmt(C->getImpexType()); +} + void OMPClauseProfiler::VisitOMPProcBindClause(const OMPProcBindClause *C) { } void OMPClauseProfiler::VisitOMPUnifiedAddressClause( diff --git a/clang/lib/CodeGen/CGOpenMPRuntime.cpp b/clang/lib/CodeGen/CGOpenMPRuntime.cpp index 01661ad54ee2f..8981a0de6d0e4 100644 --- a/clang/lib/CodeGen/CGOpenMPRuntime.cpp +++ b/clang/lib/CodeGen/CGOpenMPRuntime.cpp @@ -3855,6 +3855,7 @@ CGOpenMPRuntime::emitTaskInit(CodeGenFunction &CGF, SourceLocation Loc, PriorityFlag = 0x20, DetachableFlag = 0x40, FreeAgentFlag = 0x80, + TransparentFlag = 0x100, }; unsigned Flags = Data.Tied ? TiedFlag : 0; bool NeedsCleanup = false; @@ -3869,6 +3870,9 @@ CGOpenMPRuntime::emitTaskInit(CodeGenFunction &CGF, SourceLocation Loc, if (Kind == OMPC_THREADSET_omp_pool) Flags = Flags | FreeAgentFlag; } + if (D.getSingleClause<OMPTransparentClause>()) + Flags |= TransparentFlag; + if (Data.Priority.getInt()) Flags = Flags | PriorityFlag; if (D.hasClausesOfKind<OMPDetachClause>()) diff --git a/clang/lib/Parse/ParseOpenMP.cpp b/clang/lib/Parse/ParseOpenMP.cpp index 01fd05961f876..45f0497aeb116 100644 --- a/clang/lib/Parse/ParseOpenMP.cpp +++ b/clang/lib/Parse/ParseOpenMP.cpp @@ -3179,6 +3179,7 @@ OMPClause *Parser::ParseOpenMPClause(OpenMPDirectiveKind DKind, case OMPC_message: case OMPC_ompx_dyn_cgroup_mem: case OMPC_dyn_groupprivate: + case OMPC_transparent: // OpenMP [2.5, Restrictions] // At most one num_threads clause can appear on the directive. // OpenMP [2.8.1, simd construct, Restrictions] diff --git a/clang/lib/Sema/SemaOpenMP.cpp b/clang/lib/Sema/SemaOpenMP.cpp index 2a1337be13b99..246a2c9c90b1b 100644 --- a/clang/lib/Sema/SemaOpenMP.cpp +++ b/clang/lib/Sema/SemaOpenMP.cpp @@ -16554,6 +16554,9 @@ OMPClause *SemaOpenMP::ActOnOpenMPSingleExprClause(OpenMPClauseKind Kind, case OMPC_holds: Res = ActOnOpenMPHoldsClause(Expr, StartLoc, LParenLoc, EndLoc); break; + case OMPC_transparent: + Res = ActOnOpenMPTransparentClause(Expr, StartLoc, LParenLoc, EndLoc); + break; case OMPC_dyn_groupprivate: case OMPC_grainsize: case OMPC_num_tasks: @@ -17457,6 +17460,64 @@ OMPClause *SemaOpenMP::ActOnOpenMPThreadsetClause(OpenMPThreadsetKind Kind, OMPThreadsetClause(Kind, KindLoc, StartLoc, LParenLoc, EndLoc); } +static OMPClause *createTransparentClause(Sema &SemaRef, ASTContext &Ctx, + Expr *ImpexTypeArg, + SourceLocation StartLoc, + SourceLocation LParenLoc, + SourceLocation EndLoc) { + ExprResult ER = SemaRef.DefaultLvalueConversion(ImpexTypeArg); + if (ER.isInvalid()) + return nullptr; + + return new (Ctx) OMPTransparentClause(ER.get(), StartLoc, LParenLoc, EndLoc); +} + +OMPClause *SemaOpenMP::ActOnOpenMPTransparentClause(Expr *ImpexTypeArg, + SourceLocation StartLoc, + SourceLocation LParenLoc, + SourceLocation EndLoc) { + QualType Ty = ImpexTypeArg->getType(); + + if (const auto *TT = Ty->getAs<TypedefType>()) { + const TypedefNameDecl *TypedefDecl = TT->getDecl(); + llvm::StringRef TypedefName = TypedefDecl->getName(); + IdentifierInfo &II = SemaRef.PP.getIdentifierTable().get(TypedefName); + ParsedType ImpexTy = + SemaRef.getTypeName(II, StartLoc, SemaRef.getCurScope()); + if (!ImpexTy.getAsOpaquePtr() || ImpexTy.get().isNull()) { + SemaRef.Diag(StartLoc, diag::err_omp_implied_type_not_found) + << TypedefName; + return nullptr; + } + return createTransparentClause(SemaRef, getASTContext(), ImpexTypeArg, + StartLoc, LParenLoc, EndLoc); + } + + if (Ty->isEnumeralType()) + return createTransparentClause(SemaRef, getASTContext(), ImpexTypeArg, + StartLoc, LParenLoc, EndLoc); + + if (Ty->isIntegerType()) { + if (isNonNegativeIntegerValue(ImpexTypeArg, SemaRef, OMPC_transparent, + /*StrictlyPositive=*/false)) { + ExprResult Value = + SemaRef.OpenMP().PerformOpenMPImplicitIntegerConversion(StartLoc, + ImpexTypeArg); + if (std::optional<llvm::APSInt> Result = + Value.get()->getIntegerConstantExpr(SemaRef.Context)) { + if (Result->isNegative() || + Result > + static_cast<int64_t>(SemaOpenMP::OpenMPImpexType::OMP_Export)) + SemaRef.Diag(StartLoc, diag::err_omp_transparent_invalid_value); + } + return createTransparentClause(SemaRef, getASTContext(), ImpexTypeArg, + StartLoc, LParenLoc, EndLoc); + } + } + SemaRef.Diag(StartLoc, diag::err_omp_transparent_invalid_type) << Ty; + return nullptr; +} + OMPClause *SemaOpenMP::ActOnOpenMPProcBindClause(ProcBindKind Kind, SourceLocation KindKwLoc, SourceLocation StartLoc, diff --git a/clang/lib/Sema/TreeTransform.h b/clang/lib/Sema/TreeTransform.h index a53d578fc35ac..943719f97f9cd 100644 --- a/clang/lib/Sema/TreeTransform.h +++ b/clang/lib/Sema/TreeTransform.h @@ -1851,6 +1851,13 @@ class TreeTransform { return getSema().OpenMP().ActOnOpenMPProcBindClause( Kind, KindKwLoc, StartLoc, LParenLoc, EndLoc); } + OMPClause *RebuildOMPTransparentClause(Expr *ImpexTypeArg, + SourceLocation StartLoc, + SourceLocation LParenLoc, + SourceLocation EndLoc) { + return getSema().OpenMP().ActOnOpenMPTransparentClause( + ImpexTypeArg, StartLoc, LParenLoc, EndLoc); + } /// Build a new OpenMP 'schedule' clause. /// @@ -4322,6 +4329,14 @@ class TreeTransform { AssociatedDecl, NTTP, Loc, Arg, PackIndex, Final); } + OMPClause *RebuildOpenMPTransparentClause(Expr *ImpexType, + SourceLocation StartLoc, + SourceLocation LParenLoc, + SourceLocation EndLoc) { + return getSema().OpenMP().ActOnOpenMPTransparentClause(ImpexType, StartLoc, + LParenLoc, EndLoc); + } + private: QualType TransformTypeInObjectScope(TypeLocBuilder &TLB, TypeLoc TL, QualType ObjectType, @@ -10672,6 +10687,20 @@ TreeTransform<Derived>::TransformOMPThreadsetClause(OMPThreadsetClause *C) { return C; } +template <typename Derived> +OMPClause * +TreeTransform<Derived>::TransformOMPTransparentClause(OMPTransparentClause *C) { + Expr *Impex = C->getImpexType(); + ExprResult TransformedImpex = getDerived().TransformExpr(Impex); + + if (TransformedImpex.isInvalid()) + return nullptr; + + return getDerived().RebuildOMPTransparentClause( + TransformedImpex.get(), C->getBeginLoc(), C->getLParenLoc(), + C->getEndLoc()); +} + template <typename Derived> OMPClause * TreeTransform<Derived>::TransformOMPProcBindClause(OMPProcBindClause *C) { diff --git a/clang/lib/Serialization/ASTReader.cpp b/clang/lib/Serialization/ASTReader.cpp index f7be16e326c56..b7ea353f27385 100644 --- a/clang/lib/Serialization/ASTReader.cpp +++ b/clang/lib/Serialization/ASTReader.cpp @@ -11320,6 +11320,9 @@ OMPClause *OMPClauseReader::readClause() { case llvm::omp::OMPC_threadset: C = new (Context) OMPThreadsetClause(); break; + case llvm::omp::OMPC_transparent: + C = new (Context) OMPTransparentClause(); + break; case llvm::omp::OMPC_read: C = new (Context) OMPReadClause(); break; @@ -11737,6 +11740,11 @@ void OMPClauseReader::VisitOMPThreadsetClause(OMPThreadsetClause *C) { C->setThreadsetKind(TKind); } +void OMPClauseReader::VisitOMPTransparentClause(OMPTransparentClause *C) { + C->setLParenLoc(Record.readSourceLocation()); + C->setImpexTypeKind(Record.readSubExpr()); +} + void OMPClauseReader::VisitOMPProcBindClause(OMPProcBindClause *C) { C->setProcBindKind(static_cast<llvm::omp::ProcBindKind>(Record.readInt())); C->setLParenLoc(Record.readSourceLocation()); diff --git a/clang/lib/Serialization/ASTWriter.cpp b/clang/lib/Serialization/ASTWriter.cpp index 39104da10d0b7..e9189f9ea5238 100644 --- a/clang/lib/Serialization/ASTWriter.cpp +++ b/clang/lib/Serialization/ASTWriter.cpp @@ -7978,6 +7978,11 @@ void OMPClauseWriter::VisitOMPThreadsetClause(OMPThreadsetClause *C) { Record.writeEnum(C->getThreadsetKind()); } +void OMPClauseWriter::VisitOMPTransparentClause(OMPTransparentClause *C) { + Record.AddSourceLocation(C->getLParenLoc()); + Record.AddStmt(C->getImpexType()); +} + void OMPClauseWriter::VisitOMPProcBindClause(OMPProcBindClause *C) { Record.push_back(unsigned(C->getProcBindKind())); Record.AddSourceLocation(C->getLParenLoc()); diff --git a/clang/test/OpenMP/task_ast_print.cpp b/clang/test/OpenMP/task_ast_print.cpp index b059f187156ee..4c59a7c7fafa1 100644 --- a/clang/test/OpenMP/task_ast_print.cpp +++ b/clang/test/OpenMP/task_ast_print.cpp @@ -16,6 +16,12 @@ typedef void *omp_depend_t; typedef unsigned long omp_event_handle_t; +typedef void **omp_impex_t; +extern const omp_impex_t omp_not_impex; +extern const omp_impex_t omp_import; +extern const omp_impex_t omp_export; +extern const omp_impex_t omp_impex; + void foo() {} struct S1 { @@ -157,6 +163,41 @@ T tmain(T argc, T *argv) { enum Enum {}; +#ifdef OMP60 +typedef void **omp_impex_t; +extern const omp_impex_t omp_not_impex; +extern const omp_impex_t omp_import; +extern const omp_impex_t omp_export; +extern const omp_impex_t omp_impex; + +template <int C> +void TestTaskLoopImpex() { +#pragma omp taskloop transparent(C) + for (int i = 0; i < 10; ++i) {} +} + +enum class TaskType { + TypeA, + TypeB, + TypeC +}; + +template <typename T> +class TransparentTemplate { +public: + void TestTaskImport() { + #pragma omp task transparent(omp_import) + { + T temp; + } + } + void TestTaskLoopImpex() { + #pragma omp taskloop transparent(omp_impex) + for (int i = 0; i < 10; ++i) {} + } +}; +#endif + int main(int argc, char **argv) { long x; int b = argc, c, d, e, f, g; @@ -164,6 +205,9 @@ int main(int argc, char **argv) { int arr[10], arr1[argc]; omp_depend_t y; omp_event_handle_t evt; +#ifdef OMP60 + omp_impex_t v = omp_import; +#endif #pragma omp threadprivate(a) Enum ee; // CHECK: Enum ee; @@ -205,13 +249,57 @@ int main(int argc, char **argv) { #pragma omp task threadset(omp_pool) #pragma omp task threadset(omp_team) foo(); + +#pragma omp task transparent(omp_not_impex) +#pragma omp task transparent(omp_import) +#pragma omp task transparent(omp_export) +#pragma omp task transparent(omp_impex) +#pragma omp task transparent(omp_import) +#pragma omp task transparent(v) +#pragma omp task transparent(v ? omp_import : omp_export) +#pragma omp task transparent(omp_import + 0) +#pragma omp task transparent((v)) + foo(); + + TestTaskLoopImpex<1>(); + + TaskType task = TaskType::TypeA; +#pragma omp task transparent(task) + foo(); #endif + + // CHECK60: #pragma omp taskloop transparent(C) + // CHECK60: #pragma omp taskloop transparent(1) + // CHECK60: #pragma omp task transparent(omp_import) + // CHECK60: #pragma omp taskloop transparent(omp_impex) + // CHECK60: #pragma omp task transparent(omp_import) // CHECK60: #pragma omp task threadset(omp_pool) // CHECK60: #pragma omp task threadset(omp_team) // CHECK60-NEXT: foo(); + // CHECK60: #pragma omp task transparent(omp_not_impex) + // CHECK60-NEXT: #pragma omp task transparent(omp_import) + // CHECK60-NEXT: #pragma omp task transparent(omp_export) + // CHECK60-NEXT: #pragma omp task transparent(omp_impex) + // CHECK60-NEXT: #pragma omp task transparent(omp_import) + // CHECK60-NEXT: #pragma omp task transparent(v) + // CHECK60-NEXT: #pragma omp task transparent(v ? omp_import : omp_export) + // CHECK60-NEXT: #pragma omp task transparent(omp_import + 0) + // CHECK60-NEXT: #pragma omp task transparent((v)) + // CHECK60-NEXT: foo(); + // CHECK60: #pragma omp task transparent(task) + // CHECK60-NEXT: foo(); + return tmain<int, 5>(b, &b) + tmain<long, 1>(x, &x); } +#ifdef OMP60 +void TestTaskTransparent() { + TransparentTemplate<int> obj; + obj.TestTaskImport(); + obj.TestTaskLoopImpex(); +} +#endif + extern template int S<int>::TS; extern template long S<long>::TS; diff --git a/clang/test/OpenMP/task_codegen.cpp b/clang/test/OpenMP/task_codegen.cpp index ba8e6945de9d0..faa9c3dfbcf61 100644 --- a/clang/test/OpenMP/task_codegen.cpp +++ b/clang/test/OpenMP/task_codegen.cpp @@ -62,6 +62,12 @@ enum omp_allocator_handle_t { KMP_ALLOCATOR_MAX_HANDLE = __UINTPTR_MAX__ }; +typedef void **omp_impex_t; +extern const omp_impex_t omp_not_impex; +extern const omp_impex_t omp_import; +extern const omp_impex_t omp_export; +extern const omp_impex_t omp_impex; + struct S { int a; S() : a(0) {} @@ -231,6 +237,25 @@ void test_threadset() { } } + +void test_transparent() +{ +#pragma omp task transparent(omp_not_impex) + {} +#pragma omp task transparent(omp_import) + {} +#pragma omp task transparent(omp_export) + {} +#pragma omp task transparent(omp_impex) + {} + omp_impex_t v; +#pragma omp task transparent(v) + {} +#pragma omp task transparent(v ? omp_import : omp_export) + {} +#pragma omp task transparent(omp_import + 0) + {} +} #endif // OMP60 #endif @@ -10276,3 +10301,52 @@ void test_threadset() // CHECK6-NEXT: call i32 @__kmpc_global_thread_num(ptr @[[GLOB_PTR2:[0-9]+]]) // CHECK6-NEXT: call i32 @__kmpc_omp_task(ptr @1, i32 %omp_global_thread_num4, ptr %3) // CHECK6-NEXT: ret void + +// CHECK6-LABEL: define void @_Z16test_transparentv() #1 { +// CHECK6-NEXT: entry: +// CHECK6-NEXT: [[AGG_CAPTURED:%.*]] = alloca [[STRUCT_ANON_27:%.*]], align 1 +// CHECK6-NEXT: [[AGG_CAPTURED2:%.*]] = alloca [[STRUCT_ANON_29:%.*]], align 1 +// CHECK6-NEXT: [[AGG_CAPTURED5:%.*]] = alloca [[STRUCT_ANON_31:%.*]], align 1 +// CHECK6-NEXT: [[AGG_CAPTURED8:%.*]] = alloca [[STRUCT_ANON_33:%.*]], align 1 +// CHECK6-NEXT: [[V:%.*]] = alloca ptr, align 8 +// CHECK6-NEXT: [[AGG_CAPTURED11:%.*]] = alloca [[STRUCT_ANON_35:%.*]], align 1 +//CHECK6-NEXT: [[AGG_CAPTURED14:%.*]] = alloca [[STRUCT_ANON_37:%.*]], align 1 +// CHECK6-NEXT: [[AGG_CAPTURED17:%.*]] = alloca [[STRUCT_ANON_39:%.*]], align 1 +// CHECK6-NEXT: [[OMP_GLOBAL_THREAD_NUM:%.*]] = call i32 @__kmpc_global_thread_num(ptr @31) +// CHECK6-NEXT: [[TMP0:%.*]] = call ptr @__kmpc_omp_task_alloc(ptr @1, i32 [[OMP_GLOBAL_THREAD_NUM]], i32 257, i64 40, i64 1, ptr @.omp_task_entry..[[ENTRY1:[0-9]+]]) +// CHECK6-NEXT: [[TMP1:%.*]] = getelementptr inbounds nuw %struct.kmp_task_t_with_privates{{.*}}, ptr [[TMP0]], i32 0, i32 0 +// CHECK6-NEXT: [[OMP_GLOBAL_THREAD_NUM1:%.*]] = call i32 @__kmpc_global_thread_num(ptr @31) +// CHECK6-NEXT: [[TMP2:%.*]] = call i32 @__kmpc_omp_task(ptr @1, i32 [[OMP_GLOBAL_THREAD_NUM1]], ptr [[TMP0]]) +// CHECK6-NEXT: [[OMP_GLOBAL_THREAD_NUM3:%.*]] = call i32 @__kmpc_global_thread_num(ptr @33) +// CHECK6-NEXT: [[TMP3:%.*]] = call ptr @__kmpc_omp_task_alloc(ptr @1, i32 [[OMP_GLOBAL_THREAD_NUM3]], i32 257, i64 40, i64 1, ptr @.omp_task_entry..[[ENTRY2:[0-9]+]]) +// CHECK6-NEXT: [[TMP4:%.*]] = getelementptr inbounds nuw %struct.kmp_task_t_with_privates{{.*}}, ptr [[TMP3]], i32 0, i32 0 +// CHECK6-NEXT: [[OMP_GLOBAL_THREAD_NUM4:%.*]] = call i32 @__kmpc_global_thread_num(ptr @33) +// CHECK6-NEXT: [[TMP5:%.*]] = call i32 @__kmpc_omp_task(ptr @1, i32 [[OMP_GLOBAL_THREAD_NUM4]], ptr [[TMP3]]) +// CHECK6-NEXT: [[OMP_GLOBAL_THREAD_NUM6:%.*]] = call i32 @__kmpc_global_thread_num(ptr @35) +// CHECK6-NEXT: [[TMP6:%.*]] = call ptr @__kmpc_omp_task_alloc(ptr @1, i32 [[OMP_GLOBAL_THREAD_NUM6]], i32 257, i64 40, i64 1, ptr @.omp_task_entry..[[ENTRY3:[0-9]+]]) +// CHECK6-NEXT: [[TMP7:%.*]] = getelementptr inbounds nuw %struct.kmp_task_t_with_privates{{.*}}, ptr [[TMP6]], i32 0, i32 0 +// CHECK6-NEXT: [[OMP_GLOBAL_THREAD_NUM7:%.*]] = call i32 @__kmpc_global_thread_num(ptr @35) +// CHECK6-NEXT: [[TMP8:%.*]] = call i32 @__kmpc_omp_task(ptr @1, i32 [[OMP_GLOBAL_THREAD_NUM7]], ptr [[TMP6]]) +// CHECK6-NEXT: [[OMP_GLOBAL_THREAD_NUM9:%.*]] = call i32 @__kmpc_global_thread_num(ptr @37) +// CHECK6-NEXT: [[TMP9:%.*]] = call ptr @__kmpc_omp_task_alloc(ptr @1, i32 [[OMP_GLOBAL_THREAD_NUM9]], i32 257, i64 40, i64 1, ptr @.omp_task_entry..[[ENTRY4:[0-9]+]]) +// CHECK6-NEXT: [[TMP10:%.*]] = getelementptr inbounds nuw %struct.kmp_task_t_with_privates{{.*}}, ptr [[TMP9]], i32 0, i32 0 +// CHECK6-NEXT: [[OMP_GLOBAL_THREAD_NUM10:%.*]] = call i32 @__kmpc_global_thread_num(ptr @37) +// CHECK6-NEXT: [[TMP11:%.*]] = call i32 @__kmpc_omp_task(ptr @1, i32 [[OMP_GLOBAL_THREAD_NUM10]], ptr [[TMP9]]) +// CHECK6-NEXT: [[OMP_GLOBAL_THREAD_NUM12:%.*]] = call i32 @__kmpc_global_thread_num(ptr @39) +// CHECK6-NEXT: [[TMP12:%.*]] = call ptr @__kmpc_omp_task_alloc(ptr @1, i32 [[OMP_GLOBAL_THREAD_NUM12]], i32 257, i64 40, i64 1, ptr @.omp_task_entry..[[ENTRY37:[0-9]+]]) +// CHECK6-NEXT: [[TMP13:%.*]] = getelementptr inbounds nuw %struct.kmp_task_t_with_privates{{.*}}, ptr [[TMP12]], i32 0, i32 0 +// CHECK6-NEXT: [[OMP_GLOBAL_THREAD_NUM13:%.*]] = call i32 @__kmpc_global_thread_num(ptr @39) +// CHECK6-NEXT: [[TMP14:%.*]] = call i32 @__kmpc_omp_task(ptr @1, i32 [[OMP_GLOBAL_THREAD_NUM13]], ptr [[TMP12]]) + +// CHECK6-NEXT: [[OMP_GLOBAL_THREAD_NUM15:%.*]] = call i32 @__kmpc_global_thread_num(ptr @41) +// CHECK6-NEXT: [[TMP15:%.*]] = call ptr @__kmpc_omp_task_alloc(ptr @1, i32 [[OMP_GLOBAL_THREAD_NUM15]], i32 257, i64 40, i64 1, ptr @.omp_task_entry..[[ENTRY39:[0-9]+]]) +// CHECK6-NEXT: [[TMP16:%.*]] = getelementptr inbounds nuw %struct.kmp_task_t_with_privates{{.*}}, ptr [[TMP15]], i32 0, i32 0 +// CHECK6-NEXT: [[OMP_GLOBAL_THREAD_NUM16:%.*]] = call i32 @__kmpc_global_thread_num(ptr @41) +// CHECK6-NEXT: [[TMP17:%.*]] = call i32 @__kmpc_omp_task(ptr @1, i32 %omp_global_thread_num16, ptr [[TMP15]]) +// CHECK6-NEXT: [[OMP_GLOBAL_THREAD_NUM18:%.*]] = call i32 @__kmpc_global_thread_num(ptr @43) + // CHECK6-NEXT: [[TMP18:%.*]] = call ptr @__kmpc_omp_task_alloc(ptr @1, i32 [[OMP_GLOBAL_THREAD_NUM18]], i32 257, i64 40, i64 1, ptr @.omp_task_entry..[[ENTRY41:[0-9]+]]) + // CHECK6-NEXT: [[TMP19:%.*]] = getelementptr inbounds nuw %struct.kmp_task_t_with_privates{{.*}}, ptr [[TMP18]], i32 0, i32 0 + // CHECK6-NEXT: [[OMP_GLOBAL_THREAD_NUM19:%.*]] = call i32 @__kmpc_global_thread_num(ptr @43) + // CHECK6-NEXT: [[TMP20:%.*]] = call i32 @__kmpc_omp_task(ptr @1, i32 [[OMP_GLOBAL_THREAD_NUM19]], ptr [[TMP18]]) +// CHECK6-NEXT: ret void +// CHECK6-NEXT:} diff --git a/clang/test/OpenMP/task_transparent_messages.cpp b/clang/test/OpenMP/task_transparent_messages.cpp new file mode 100644 index 0000000000000..a58df6ba2a77b --- /dev/null +++ b/clang/test/OpenMP/task_transparent_messages.cpp @@ -0,0 +1,74 @@ +// RUN: %clang_cc1 -verify=expected,omp45 -fopenmp -fopenmp-version=45 -std=c++11 -ferror-limit 200 -o - %s +// RUN: %clang_cc1 -verify=expected,omp50 -fopenmp -fopenmp-version=50 -std=c++11 -ferror-limit 200 -o - %s +// RUN: %clang_cc1 -verify=expected,omp51 -fopenmp -fopenmp-version=51 -std=c++11 -ferror-limit 200 -o - %s +// RUN: %clang_cc1 -verify=expected,omp60 -DOMP60 -fopenmp -fopenmp-version=60 -ferror-limit 200 -o - %s + +// RUN: %clang_cc1 -verify=expected,omp45 -fopenmp-simd -fopenmp-version=45 -std=c++11 -ferror-limit 200 -o - %s +// RUN: %clang_cc1 -verify=expected,omp50 -fopenmp-simd -fopenmp-version=50 -std=c++11 -ferror-limit 200 -o - %s +// RUN: %clang_cc1 -verify=expected,omp51 -fopenmp-simd -fopenmp-version=51 -std=c++11 -ferror-limit 200 -o - %s +// RUN: %clang_cc1 -verify=expected,omp60 -DOMP60 -fopenmp-simd -fopenmp-version=60 -std=c++11 -ferror-limit 200 -o - %s + +#ifdef OMP60 +struct ComplexStruct { + int data[10]; + struct InnerStruct { + float value; + } inner; +}; + +void TestTaskTransparentWithErrors() { + int x = 10; + int* ptr = &x; + int arr[5]; +#pragma omp task transparent() // expected-error{{expected expression}} + // expected-error@+1{{use of undeclared identifier 'omp_not_impex'}} +#pragma omp task transparent(omp_not_impex) + // expected-error@+1{{use of undeclared identifier 'omp_import'}} +#pragma omp task transparent(omp_import) + // expected-error@+1{{use of undeclared identifier 'omp_export'}} +#pragma omp task transparent(omp_export) + // expected-error@+1{{use of undeclared identifier 'omp_impex'}} +#pragma omp task transparent(omp_impex) + // expected-error@+1{{invalid value for transparent clause, expected one of: omp_not_impex, omp_import, omp_export, omp_impex}} +#pragma omp task transparent(5) + // expected-error@+1{{transparent clause cannot be applied to type: 'int *'}} +#pragma omp task transparent(ptr) + // expected-error@+1{{transparent clause cannot be applied to type: 'int *'}} +#pragma omp task transparent(&x) + // expected-error@+1{{transparent clause cannot be applied to type: 'double'}} +#pragma omp task transparent(20.0) + // expected-error@+1{{transparent clause cannot be applied to type: 'int[5]'}} +#pragma omp task transparent(arr) + for (int i = 0; i < 5; ++i) {} +} + +typedef void **omp_impex_t; +extern const omp_impex_t omp_not_impex; // omp60-note {{'omp_not_impex' declared here}} +extern const omp_impex_t omp_import; +extern const omp_impex_t omp_export; +extern const omp_impex_t omp_impex; + +int invalid_arg; +void TestTaskTransparentInvalidArgs() { +#pragma omp task transparent(omp_import, omp_not_import) // expected-error{{expected ')'}} // expected-note{{to match this '('}} + #pragma omp task transparent() // expected-error {{expected expression}} + {} +} + +void TestTaskLoopTransparentInvalidArgs() { +#pragma omp taskloop transparent(omp_not_import, omp_import) // expected-error{{expected ')'}} // expected-note{{to match this '('}} // expected-error{{use of undeclared identifier 'omp_not_import'; did you mean 'omp_not_impex'?}} + for (int i = 0; i < 10; ++i) {} + #pragma omp taskloop transparent() // expected-error {{expected expression}} + for (int i = 0; i < 10; ++i) {} +} + +#else +void TransparentClauseNotSupported() { + #pragma omp task transparent(omp_pool) // omp45-error {{unexpected OpenMP clause 'transparent' in directive '#pragma omp task'}} omp45-error {{use of undeclared identifier 'omp_pool'}} omp50-error {{unexpected OpenMP clause 'transparent' in directive '#pragma omp task'}} omp50-error {{use of undeclared identifier 'omp_pool'}} omp51-error {{unexpected OpenMP clause 'transparent' in directive '#pragma omp task'}} omp51-error {{use of undeclared identifier 'omp_pool'}} + #pragma omp task transparent(omp_team) // omp45-error {{unexpected OpenMP clause 'transparent' in directive '#pragma omp task'}} omp45-error {{use of undeclared identifier 'omp_team'}} omp50-error {{unexpected OpenMP clause 'transparent' in directive '#pragma omp task'}} omp50-error {{use of undeclared identifier 'omp_team'}} omp51-error {{unexpected OpenMP clause 'transparent' in directive '#pragma omp task'}} omp51-error {{use of undeclared identifier 'omp_team'}} + #pragma omp taskloop transparent(omp_team) // omp45-error {{unexpected OpenMP clause 'transparent' in directive '#pragma omp taskloop'}} omp45-error {{use of undeclared identifier 'omp_team'}} omp50-error {{unexpected OpenMP clause 'transparent' in directive '#pragma omp taskloop'}} omp50-error {{use of undeclared identifier 'omp_team'}} omp51-error {{unexpected OpenMP clause 'transparent' in directive '#pragma omp taskloop'}} omp51-error {{use of undeclared identifier 'omp_team'}} + for (int i = 0; i < 10; ++i) {} + #pragma omp taskloop transparent(omp_pool) // omp45-error {{unexpected OpenMP clause 'transparent' in directive '#pragma omp taskloop'}} omp45-error {{use of undeclared identifier 'omp_pool'}} omp50-error {{unexpected OpenMP clause 'transparent' in directive '#pragma omp taskloop'}} omp50-error {{use of undeclared identifier 'omp_pool'}} omp51-error {{unexpected OpenMP clause 'transparent' in directive '#pragma omp taskloop'}} omp51-error {{use of undeclared identifier 'omp_pool'}} + for (int i = 0; i < 10; ++i) {} +} +#endif diff --git a/clang/test/OpenMP/task_transparent_serialization.cpp b/clang/test/OpenMP/task_transparent_serialization.cpp new file mode 100644 index 0000000000000..110bd608b41ab --- /dev/null +++ b/clang/test/OpenMP/task_transparent_serialization.cpp @@ -0,0 +1,118 @@ +// RUN: %clang_cc1 -fopenmp -fopenmp-version=60 -x c++ -std=c++11 -emit-pch -o %t %s +// RUN: %clang_cc1 -fopenmp -fopenmp-version=60 -x c++ -std=c++11 -include-pch %t -ast-dump-all %s | FileCheck %s + +// expected-no-diagnostics +#ifndef HEADER +#define HEADER + +typedef void **omp_impex_t; +extern const omp_impex_t omp_not_impex; +extern const omp_impex_t omp_import; +extern const omp_impex_t omp_export; +extern const omp_impex_t omp_impex; + +template <typename T> +class TransparentTemplate { +public: + void TestTaskLoopImpex() { + #pragma omp taskloop transparent(omp_impex) + for (int i = 0; i < 10; ++i) {} + } +}; + +void TestTaskTransparent() { + int a; + omp_impex_t imp; +#pragma omp task transparent(omp_not_impex) +#pragma omp task transparent(imp) + +#pragma omp parallel + { +#pragma omp task transparent(omp_export) + { +#pragma omp taskloop transparent(omp_impex) + for (int i = 0; i < 5; ++i) {} + } + } + TransparentTemplate<int> obj; + obj.TestTaskLoopImpex(); +} +#endif + + +// CHECK: FunctionDecl {{.*}} TestTaskTransparent 'void ()' +// CHECK: OMPTaskDirective +// CHECK-NEXT: OMPTransparentClause +// CHECK-NEXT: ImplicitCastExpr {{.*}} 'omp_impex_t':'void **' <LValueToRValue> +// CHECK-NEXT: DeclRefExpr {{.*}} 'const omp_impex_t':'void **const' lvalue Var {{.*}} 'omp_not_impex' 'const omp_impex_t':'void **const' +// CHECK-NEXT: OMPFirstprivateClause +// CHECK-NEXT: DeclRefExpr {{.*}} 'omp_impex_t':'void **' lvalue Var {{.*}} 'imp' 'omp_impex_t':'void **' refers_to_enclosing_variable_or_capture +// CHECK-NEXT: CapturedStmt +// CHECK: OMPTaskDirective +// CHECK-NEXT: OMPTransparentClause +// CHECK-NEXT: ImplicitCastExpr {{.*}} 'omp_impex_t':'void **' <LValueToRValue> +// CHECK-NEXT: DeclRefExpr {{.*}} 'omp_impex_t':'void **' lvalue Var {{.*}} 'imp' 'omp_impex_t':'void **' refers_to_enclosing_variable_or_capture +// CHECK-NEXT: CapturedStmt +// CHECK: OMPTaskDirective +// CHECK-NEXT: OMPTransparentClause +// CHECK-NEXT: ImplicitCastExpr {{.*}} 'omp_impex_t':'void **' <LValueToRValue> +// CHECK-NEXT: DeclRefExpr {{.*}} 'const omp_impex_t':'void **const' lvalue Var {{.*}} 'omp_export' 'const omp_impex_t':'void **const' +// CHECK-NEXT: CapturedStmt +// CHECK: OMPTaskLoopDirective +// CHECK-NEXT: OMPTransparentClause +// CHECK-NEXT: ImplicitCastExpr {{.*}} 'omp_impex_t':'void **' <LValueToRValue> +// CHECK-NEXT: DeclRefExpr {{.*}} 'const omp_impex_t':'void **const' lvalue Var {{.*}} 'omp_impex' 'const omp_impex_t':'void **const' +// CHECK-NEXT: CapturedStmt +// CHECK: OMPTaskLoopDirective +// CHECK-NEXT: OMPTransparentClause +// CHECK-NEXT: ImplicitCastExpr {{.*}} 'omp_impex_t':'void **' <LValueToRValue> +// CHECK-NEXT: DeclRefExpr {{.*}} 'const omp_impex_t':'void **const' lvalue Var {{.*}} 'omp_impex' 'const omp_impex_t':'void **const' +// CHECK-NEXT: CapturedStmt +// CHECK: OMPTaskDirective +// CHECK-NEXT: OMPTransparentClause +// CHECK-NEXT: ImplicitCastExpr {{.*}} 'omp_impex_t':'void **' <LValueToRValue> +// CHECK-NEXT: DeclRefExpr {{.*}} 'const omp_impex_t':'void **const' lvalue Var {{.*}} 'omp_export' 'const omp_impex_t':'void **const' +// CHECK-NEXT: CapturedStmt +// CHECK: OMPTaskLoopDirective +// CHECK-NEXT: OMPTransparentClause +// CHECK-NEXT: ImplicitCastExpr {{.*}} 'omp_impex_t':'void **' <LValueToRValue> +// CHECK-NEXT: DeclRefExpr {{.*}} 'const omp_impex_t':'void **const' lvalue Var {{.*}} 'omp_impex' 'const omp_impex_t':'void **const' +// CHECK-NEXT: CapturedStmt +// CHECK: OMPTaskLoopDirective +// CHECK-NEXT: OMPTransparentClause +// CHECK-NEXT: ImplicitCastExpr {{.*}} 'omp_impex_t':'void **' <LValueToRValue> +// CHECK-NEXT: DeclRefExpr {{.*}} 'const omp_impex_t':'void **const' lvalue Var {{.*}} 'omp_impex' 'const omp_impex_t':'void **const' +// CHECK-NEXT: CapturedStmt +// CHECK: OMPTaskDirective +// CHECK-NEXT: OMPTransparentClause +// CHECK-NEXT: ImplicitCastExpr {{.*}} 'omp_impex_t':'void **' <LValueToRValue> +// CHECK-NEXT: DeclRefExpr {{.*}} 'const omp_impex_t':'void **const' lvalue Var {{.*}} 'omp_export' 'const omp_impex_t':'void **const' +// CHECK-NEXT: CapturedStmt +// CHECK: OMPTaskLoopDirective +// CHECK-NEXT: OMPTransparentClause +// CHECK-NEXT: ImplicitCastExpr {{.*}} 'omp_impex_t':'void **' <LValueToRValue> +// CHECK-NEXT: DeclRefExpr {{.*}} 'const omp_impex_t':'void **const' lvalue Var {{.*}} 'omp_impex' 'const omp_impex_t':'void **const' +// CHECK-NEXT: CapturedStmt +// CHECK: OMPTaskLoopDirective +// CHECK-NEXT: OMPTransparentClause +// CHECK-NEXT: ImplicitCastExpr {{.*}} 'omp_impex_t':'void **' <LValueToRValue> +// CHECK-NEXT: DeclRefExpr {{.*}} 'const omp_impex_t':'void **const' lvalue Var {{.*}} 'omp_impex' 'const omp_impex_t':'void **const' +// CHECK-NEXT: CapturedStmt +// CHECK: OMPTaskDirective +// CHECK-NEXT: OMPTransparentClause +// CHECK-NEXT: ImplicitCastExpr {{.*}} 'omp_impex_t':'void **' <LValueToRValue> +// CHECK-NEXT: DeclRefExpr {{.*}} 'const omp_impex_t':'void **const' lvalue Var {{.*}} 'omp_export' 'const omp_impex_t':'void **const' +// CHECK-NEXT: CapturedStmt +// CHECK: OMPTaskLoopDirective +// CHECK-NEXT: OMPTransparentClause +// CHECK-NEXT: ImplicitCastExpr {{.*}} 'omp_impex_t':'void **' <LValueToRValue> +// CHECK-NEXT: DeclRefExpr {{.*}} 'const omp_impex_t':'void **const' lvalue Var {{.*}} 'omp_impex' 'const omp_impex_t':'void **const' +// CHECK-NEXT: CapturedStmt +// CHECK: OMPTaskLoopDirective +// CHECK-NEXT: OMPTransparentClause +// CHECK-NEXT: ImplicitCastExpr {{.*}} 'omp_impex_t':'void **' <LValueToRValue> +// CHECK-NEXT: DeclRefExpr {{.*}} 'const omp_impex_t':'void **const' lvalue Var {{.*}} 'omp_impex' 'const omp_impex_t':'void **const' +// CHECK-NEXT: CapturedStmt + + + diff --git a/clang/test/OpenMP/taskloop_ast_print.cpp b/clang/test/OpenMP/taskloop_ast_print.cpp index e4bf20af5d78e..9bca586937347 100644 --- a/clang/test/OpenMP/taskloop_ast_print.cpp +++ b/clang/test/OpenMP/taskloop_ast_print.cpp @@ -12,6 +12,12 @@ #ifndef HEADER #define HEADER +typedef void **omp_impex_t; +extern const omp_impex_t omp_not_impex; +extern const omp_impex_t omp_import; +extern const omp_impex_t omp_export; +extern const omp_impex_t omp_impex; + void foo() {} template <class T, int N> @@ -97,12 +103,34 @@ int main(int argc, char **argv) { foo(); } } + +#pragma omp taskloop transparent(omp_not_impex) + for (int i = 0; i < 10; ++i) { +#pragma omp task transparent(omp_import) + for (int i = 0; i < 10; ++i) { +#pragma omp task transparent(omp_export) + for (int i = 0; i < 10; ++i) { +#pragma omp task transparent(omp_impex) + foo(); + } + } + } #endif // CHECK60: #pragma omp taskloop threadset(omp_team) // CHECK60-NEXT: for (int i = 0; i < 10; ++i) { // CHECK60: #pragma omp taskloop threadset(omp_pool) // CHECK60-NEXT: for (int j = 0; j < 10; ++j) { // CHECK60-NEXT: foo(); + +// CHECK60: #pragma omp taskloop transparent(omp_not_impex) +// CHECK60-NEXT: for (int i = 0; i < 10; ++i) { +// CHECK60-NEXT: #pragma omp task transparent(omp_import) +// CHECK60-NEXT: for (int i = 0; i < 10; ++i) { +// CHECK60-NEXT: #pragma omp task transparent(omp_export) +// CHECK60-NEXT: for (int i = 0; i < 10; ++i) { +// CHECK60-NEXT: #pragma omp task transparent(omp_impex) +// CHECK60-NEXT: foo(); + return (tmain<int, 5>(argc) + tmain<char, 1>(argv[0][0])); } diff --git a/clang/test/OpenMP/taskloop_codegen.cpp b/clang/test/OpenMP/taskloop_codegen.cpp index d1197607a2684..9073a2376f5b4 100644 --- a/clang/test/OpenMP/taskloop_codegen.cpp +++ b/clang/test/OpenMP/taskloop_codegen.cpp @@ -15,6 +15,12 @@ #ifndef HEADER #define HEADER +typedef void **omp_impex_t; +extern const omp_impex_t omp_not_impex; +extern const omp_impex_t omp_import; +extern const omp_impex_t omp_export; +extern const omp_impex_t omp_impex; + // CHECK-LABEL: @main int main(int argc, char **argv) { // CHECK: [[GTID:%.+]] = call i32 @__kmpc_global_thread_num(ptr [[DEFLOC:@.+]]) @@ -256,6 +262,23 @@ void test_threadset() for (int i = 0; i < 10; ++i) { } } + +void test_transparent() +{ +#pragma omp taskloop transparent(omp_not_impex) + for (int i = 0; i < 10; ++i) { + } +#pragma omp taskloop transparent(omp_import) + for (int i = 0; i < 10; ++i) { + } +#pragma omp taskloop transparent(omp_export) + for (int i = 0; i < 10; ++i) { + } +#pragma omp taskloop transparent(omp_impex) + for (int i = 0; i < 10; ++i) { + } +} + #endif // OMP60 // CHECK6-LABEL: define void @_Z14test_threadsetv() // CHECK6-NEXT: entry: @@ -294,4 +317,74 @@ void test_threadset() // CHECK6-NEXT: call void @__kmpc_end_taskgroup(ptr @1, i32 %[[TID0:.*]]) // CHECK6-NEXT: ret void +// CHECK6: define void @_Z16test_transparentv +// CHECK6: entry: +// CHECK6: [[AGG_CAPTURED:%.*]] = alloca [[STRUCT_ANON_18:%.*]], align 1 +// CHECK6: [[TMP:%.*]] = alloca i32, align 4 +// CHECK6: [[AGG_CAPTURED1:%.*]] = alloca [[STRUCT_ANON_20:%.*]], align 1 +// CHECK6: [[TMP2:%.*]] = alloca i32, align 4 +// CHECK6: [[AGG_CAPTURED3:%.*]] = alloca [[STRUCT_ANON_22:%.*]], align 1 +// CHECK6: [[TMP4:%.*]] = alloca i32, align 4 +// CHECK6: [[AGG_CAPTURED5:%.*]] = alloca [[STRUCT_ANON_24:%.*]], align 1 +// CHECK6: [[TMP6:%.*]] = alloca i32, align 4 +// CHECK6: [[TMP0:%.*]] = call i32 @__kmpc_global_thread_num(ptr @1) +// CHECK6: call void @__kmpc_taskgroup(ptr @1, i32 [[TMP0]]) +// CHECK6: [[TMP1:%.*]] = call ptr @__kmpc_omp_task_alloc(ptr @1, i32 [[TMP0]], i32 257, i64 80, i64 1, ptr @.omp_task_entry..[[ENTRY1:[0-9]+]]) +// CHECK6: [[TMP2:%.*]] = getelementptr inbounds nuw %struct.kmp_task_t_with_privates{{.*}}, ptr [[TMP1]], i32 0, i32 0 +// CHECK6: [[TMP3:%.*]] = getelementptr inbounds nuw %struct.kmp_task_t{{.*}}, ptr [[TMP2]], i32 0, i32 5 +// CHECK6: store i64 0, ptr [[TMP3]], align 8 +// CHECK6: [[TMP4:%.*]] = getelementptr inbounds nuw %struct.kmp_task_t{{.*}}, ptr [[TMP2]], i32 0, i32 6 +// CHECK6: store i64 9, ptr [[TMP4]], align 8 +// CHECK6: [[TMP5:%.*]] = getelementptr inbounds nuw %struct.kmp_task_t{{.*}}, ptr [[TMP2]], i32 0, i32 7 +// CHECK6: store i64 1, ptr [[TMP5]], align 8 +// CHECK6: [[TMP6:%.*]] = getelementptr inbounds nuw %struct.kmp_task_t{{.*}}, ptr [[TMP2]], i32 0, i32 9 +// CHECK6: call void @llvm.memset.p0.i64(ptr align 8 [[TMP6]], i8 0, i64 8, i1 false) +// CHECK6: [[TMP7:%.*]] = load i64, ptr [[TMP5]], align 8 +// CHECK6: call void @__kmpc_taskloop(ptr @1, i32 [[TMP0]], ptr [[TMP1]], i32 1, ptr [[TMP3]], ptr [[TMP4]], i64 [[TMP7]], i32 1, i32 0, i64 0, ptr null) +// CHECK6: call void @__kmpc_end_taskgroup(ptr @1, i32 [[TMP0]]) +// CHECK6: call void @__kmpc_taskgroup(ptr @1, i32 [[TMP0]]) +// CHECK6: [[TMP8:%.*]] = call ptr @__kmpc_omp_task_alloc(ptr @1, i32 [[TMP0]], i32 257, i64 80, i64 1, ptr @.omp_task_entry..[[ENTRY2:[0-9]+]]) +// CHECK6: [[TMP9:%.*]] = getelementptr inbounds nuw %struct.kmp_task_t_with_privates{{.*}}, ptr [[TMP8]], i32 0, i32 0 +// CHECK6: [[TMP10:%.*]] = getelementptr inbounds nuw %struct.kmp_task_t{{.*}}, ptr [[TMP9]], i32 0, i32 5 +// CHECK6: store i64 0, ptr [[TMP10]], align 8 +// CHECK6: [[TMP11:%.*]] = getelementptr inbounds nuw %struct.kmp_task_t{{.*}}, ptr [[TMP9]], i32 0, i32 6 +// CHECK6: store i64 9, ptr [[TMP11]], align 8 +// CHECK6: [[TMP12:%.*]] = getelementptr inbounds nuw %struct.kmp_task_t{{.*}}, ptr [[TMP9]], i32 0, i32 7 +// CHECK6: store i64 1, ptr [[TMP12]], align 8 +// CHECK6: [[TMP13:%.*]] = getelementptr inbounds nuw %struct.kmp_task_t{{.*}}, ptr [[TMP9]], i32 0, i32 9 +// CHECK6: call void @llvm.memset.p0.i64(ptr align 8 [[TMP13]], i8 0, i64 8, i1 false) +// CHECK6: [[TMP14:%.*]] = load i64, ptr [[TMP12]], align 8 +// CHECK6: call void @__kmpc_taskloop(ptr @1, i32 [[TMP0]], ptr [[TMP8]], i32 1, ptr [[TMP10]], ptr [[TMP11]], i64 [[TMP14]], i32 1, i32 0, i64 0, ptr null) +// CHECK6: call void @__kmpc_end_taskgroup(ptr @1, i32 [[TMP0]]) +// CHECK6: call void @__kmpc_taskgroup(ptr @1, i32 [[TMP0]]) +// CHECK6: [[TMP15:%.*]] = call ptr @__kmpc_omp_task_alloc(ptr @1, i32 [[TMP0]], i32 257, i64 80, i64 1, ptr @.omp_task_entry..22) +// CHECK6: [[TMP16:%.*]] = getelementptr inbounds nuw %struct.kmp_task_t_with_privates{{.*}}, ptr [[TMP15]], i32 0, i32 0 +// CHECK6: [[TMP17:%.*]] = getelementptr inbounds nuw %struct.kmp_task_t{{.*}}, ptr [[TMP16]], i32 0, i32 5 +// CHECK6: store i64 0, ptr [[TMP17]], align 8 +// CHECK6: [[TMP18:%.*]] = getelementptr inbounds nuw %struct.kmp_task_t{{.*}}, ptr [[TMP16]], i32 0, i32 6 +// CHECK6: store i64 9, ptr [[TMP18]], align 8 +// CHECK6: [[TMP19:%.*]] = getelementptr inbounds nuw %struct.kmp_task_t{{.*}}, ptr [[TMP16]], i32 0, i32 7 +// CHECK6: store i64 1, ptr [[TMP19]], align 8 +// CHECK6: [[TMP20:%.*]] = getelementptr inbounds nuw %struct.kmp_task_t{{.*}}, ptr [[TMP16]], i32 0, i32 9 +// CHECK6: call void @llvm.memset.p0.i64(ptr align 8 [[TMP20]], i8 0, i64 8, i1 false) +// CHECK6: [[TMP21:%.*]] = load i64, ptr [[TMP19]], align 8 +// CHECK6: call void @__kmpc_taskloop(ptr @1, i32 [[TMP0]], ptr [[TMP15]], i32 1, ptr [[TMP17]], ptr [[TMP18]], i64 [[TMP21]], i32 1, i32 0, i64 0, ptr null) +// CHECK6: call void @__kmpc_end_taskgroup(ptr @1, i32 [[TMP0]]) +// CHECK6: call void @__kmpc_taskgroup(ptr @1, i32 [[TMP0]]) +// CHECK6: [[TMP22:%.*]] = call ptr @__kmpc_omp_task_alloc(ptr @1, i32 [[TMP0]], i32 257, i64 80, i64 1, ptr @.omp_task_entry..24) +// CHECK6: [[TMP23:%.*]] = getelementptr inbounds nuw %struct.kmp_task_t_with_privates{{.*}}, ptr [[TMP22]], i32 0, i32 0 +// CHECK6: [[TMP24:%.*]] = getelementptr inbounds nuw %struct.kmp_task_t{{.*}}, ptr [[TMP23]], i32 0, i32 5 +// CHECK6: store i64 0, ptr [[TMP24]], align 8 +// CHECK6: [[TMP25:%.*]] = getelementptr inbounds nuw %struct.kmp_task_t{{.*}}, ptr [[TMP23]], i32 0, i32 6 +// CHECK6: store i64 9, ptr [[TMP25]], align 8 +// CHECK6: [[TMP26:%.*]] = getelementptr inbounds nuw %struct.kmp_task_t{{.*}}, ptr [[TMP23]], i32 0, i32 7 +// CHECK6: store i64 1, ptr [[TMP26]], align 8 +// CHECK6: [[TMP27:%.*]] = getelementptr inbounds nuw %struct.kmp_task_t{{.*}}, ptr [[TMP23]], i32 0, i32 9 +// CHECK6: call void @llvm.memset.p0.i64(ptr align 8 [[TMP27]], i8 0, i64 8, i1 false) +// CHECK6: [[TMP28:%.*]] = load i64, ptr [[TMP26]], align 8 +// CHECK6: call void @__kmpc_taskloop(ptr @1, i32 [[TMP0]], ptr [[TMP22]], i32 1, ptr [[TMP24]], ptr [[TMP25]], i64 [[TMP28]], i32 1, i32 0, i64 0, ptr null) +// CHECK6: call void @__kmpc_end_taskgroup(ptr @1, i32 [[TMP0]]) +// CHECK6: ret void +// CHECK6:} + #endif diff --git a/clang/tools/libclang/CIndex.cpp b/clang/tools/libclang/CIndex.cpp index 32e84248c1b27..15eec87652451 100644 --- a/clang/tools/libclang/CIndex.cpp +++ b/clang/tools/libclang/CIndex.cpp @@ -2409,6 +2409,11 @@ void OMPClauseEnqueue::VisitOMPFailClause(const OMPFailClause *) {} void OMPClauseEnqueue::VisitOMPThreadsetClause(const OMPThreadsetClause *) {} +void OMPClauseEnqueue::VisitOMPTransparentClause( + const OMPTransparentClause *C) { + Visitor->AddStmt(C->getImpexType()); +} + void OMPClauseEnqueue::VisitOMPAbsentClause(const OMPAbsentClause *) {} void OMPClauseEnqueue::VisitOMPHoldsClause(const OMPHoldsClause *) {} diff --git a/llvm/include/llvm/Frontend/OpenMP/ClauseT.h b/llvm/include/llvm/Frontend/OpenMP/ClauseT.h index 898961499c473..05ee1ae36a23d 100644 --- a/llvm/include/llvm/Frontend/OpenMP/ClauseT.h +++ b/llvm/include/llvm/Frontend/OpenMP/ClauseT.h @@ -1264,7 +1264,7 @@ struct ToT { std::tuple<OPT(Expectation), OPT(Mappers), OPT(Iterator), LocatorList> t; }; -// [6.0:440-441] `transparent` clause +// [6.0:510:25] `transparent` clause template <typename T, typename I, typename E> // struct TransparentT { using IncompleteTrait = std::true_type; diff --git a/llvm/include/llvm/Frontend/OpenMP/OMP.td b/llvm/include/llvm/Frontend/OpenMP/OMP.td index 391cddaa54676..b5d262aec63d0 100644 --- a/llvm/include/llvm/Frontend/OpenMP/OMP.td +++ b/llvm/include/llvm/Frontend/OpenMP/OMP.td @@ -581,6 +581,7 @@ def OMPC_To : Clause<[Spelling<"to">]> { let flangClass = "OmpToClause"; } def OMPC_Transparent : Clause<[Spelling<"transparent">]> { + let clangClass = "OMPTransparentClause"; let flangClass = "OmpTransparentClause"; let isValueOptional = true; } _______________________________________________ cfe-commits mailing list [email protected] https://lists.llvm.org/cgi-bin/mailman/listinfo/cfe-commits
