[clang] bde808b - [CLANG][OpenMP] Add support for OpenMP6.0 transparent clause. (#174646)
via cfe-commits
cfe-commits at lists.llvm.org
Thu Jan 15 06:48:30 PST 2026
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 at +1{{use of undeclared identifier 'omp_not_impex'}}
+#pragma omp task transparent(omp_not_impex)
+ // expected-error at +1{{use of undeclared identifier 'omp_import'}}
+#pragma omp task transparent(omp_import)
+ // expected-error at +1{{use of undeclared identifier 'omp_export'}}
+#pragma omp task transparent(omp_export)
+ // expected-error at +1{{use of undeclared identifier 'omp_impex'}}
+#pragma omp task transparent(omp_impex)
+ // expected-error at +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 at +1{{transparent clause cannot be applied to type: 'int *'}}
+#pragma omp task transparent(ptr)
+ // expected-error at +1{{transparent clause cannot be applied to type: 'int *'}}
+#pragma omp task transparent(&x)
+ // expected-error at +1{{transparent clause cannot be applied to type: 'double'}}
+#pragma omp task transparent(20.0)
+ // expected-error at +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;
}
More information about the cfe-commits
mailing list