[llvm] [clang] [openmp] [OpenMP] Introduce support for OMPX extensions and taskgraph frontend (PR #66919)
via llvm-commits
llvm-commits at lists.llvm.org
Sun Nov 5 09:10:36 PST 2023
https://github.com/Munesanz updated https://github.com/llvm/llvm-project/pull/66919
>From 5314fbb92feb078e36e0ec917fe87bd6dc05e12a Mon Sep 17 00:00:00 2001
From: Adrian Munera <adrian.munera at bsc.es>
Date: Thu, 14 Sep 2023 10:57:22 +0000
Subject: [PATCH 1/3] [OpenMP] Introduce support for OMPX extensions and
taskgraph frontend
This patch introduces initial support for OpenMP experimental directives and clauses through the "ompx" sentinel. The "taskgraph" ompx directive frontend is implemented as a use case to interface with the existing OpenMP host runtime support for record and replay.
The taskgraph directive generates an outlined region where instantiated tasks are recorded and replayed in subsequent executions, using the record & replay mechanism. The "__kmpc_taskgraph" function is implemented in the OpenMP runtime to wrap the existing "__kmpc_start_record_task" and "__kmpc_end_record_task" functions within the associated statement.
The macro "OMPX_TASKGRAPH," previously necessary for building the record and replay mechanism, has been removed, as the record and replay mechanism has been tested in previous patches. The tests have been updated to make use of the new taskgraph directive instead of relying on raw runtime calls.
---
clang/include/clang-c/Index.h | 6 +-
clang/include/clang/AST/RecursiveASTVisitor.h | 3 +
clang/include/clang/AST/StmtOpenMP.h | 49 ++++++
.../clang/Basic/DiagnosticParseKinds.td | 8 +
clang/include/clang/Basic/StmtNodes.td | 1 +
clang/include/clang/Basic/TokenKinds.def | 3 +
clang/include/clang/Parse/Parser.h | 12 +-
clang/include/clang/Sema/Sema.h | 4 +
.../include/clang/Serialization/ASTBitCodes.h | 1 +
clang/lib/AST/StmtOpenMP.cpp | 15 ++
clang/lib/AST/StmtPrinter.cpp | 5 +
clang/lib/AST/StmtProfile.cpp | 4 +
clang/lib/Basic/OpenMPKinds.cpp | 3 +
clang/lib/CodeGen/CGOpenMPRuntime.cpp | 74 +++++++++
clang/lib/CodeGen/CGOpenMPRuntime.h | 8 +
clang/lib/CodeGen/CGOpenMPRuntimeGPU.cpp | 2 +
clang/lib/CodeGen/CGStmt.cpp | 3 +
clang/lib/CodeGen/CGStmtOpenMP.cpp | 6 +
clang/lib/CodeGen/CodeGenFunction.h | 1 +
.../lib/Frontend/PrintPreprocessedOutput.cpp | 7 +
clang/lib/Parse/ParseCXXInlineMethods.cpp | 7 +
clang/lib/Parse/ParseDecl.cpp | 9 ++
clang/lib/Parse/ParseDeclCXX.cpp | 24 ++-
clang/lib/Parse/ParseOpenMP.cpp | 76 +++++++++-
clang/lib/Parse/ParsePragma.cpp | 75 ++++++++-
clang/lib/Parse/ParseStmt.cpp | 1 +
clang/lib/Parse/Parser.cpp | 6 +
clang/lib/Sema/SemaExceptionSpec.cpp | 1 +
clang/lib/Sema/SemaOpenMP.cpp | 26 ++++
clang/lib/Sema/TreeTransform.h | 11 ++
clang/lib/Serialization/ASTReaderStmt.cpp | 10 ++
clang/lib/Serialization/ASTWriter.cpp | 1 +
clang/lib/Serialization/ASTWriterStmt.cpp | 6 +
clang/lib/StaticAnalyzer/Core/ExprEngine.cpp | 1 +
.../test/OpenMP/ompx_extensions_messages.cpp | 12 ++
.../test/OpenMP/ompx_taskgraph_ast_print.cpp | 34 +++++
clang/test/OpenMP/ompx_taskgraph_codegen.cpp | 29 ++++
clang/tools/libclang/CIndex.cpp | 2 +
clang/tools/libclang/CXCursor.cpp | 3 +
.../llvm/Frontend/Directive/DirectiveBase.td | 6 +
llvm/include/llvm/Frontend/OpenMP/OMP.td | 5 +
.../include/llvm/Frontend/OpenMP/OMPKinds.def | 1 +
llvm/include/llvm/TableGen/DirectiveEmitter.h | 2 +
llvm/test/TableGen/directive1.td | 22 +++
llvm/test/TableGen/directive2.td | 22 +++
llvm/utils/TableGen/DirectiveEmitter.cpp | 72 +++++++++
openmp/runtime/CMakeLists.txt | 5 -
openmp/runtime/src/kmp.h | 19 +--
openmp/runtime/src/kmp_config.h.cmake | 2 -
openmp/runtime/src/kmp_global.cpp | 4 +-
openmp/runtime/src/kmp_settings.cpp | 4 -
openmp/runtime/src/kmp_taskdeps.cpp | 16 +-
openmp/runtime/src/kmp_taskdeps.h | 4 -
openmp/runtime/src/kmp_tasking.cpp | 143 +++++++-----------
openmp/runtime/test/CMakeLists.txt | 1 -
openmp/runtime/test/lit.cfg | 3 -
openmp/runtime/test/lit.site.cfg.in | 1 -
.../test/tasking/omp_record_replay.cpp | 7 +-
.../test/tasking/omp_record_replay_deps.cpp | 7 +-
.../tasking/omp_record_replay_multiTDGs.cpp | 12 +-
.../tasking/omp_record_replay_print_dot.cpp | 12 +-
.../tasking/omp_record_replay_taskloop.cpp | 7 +-
62 files changed, 737 insertions(+), 189 deletions(-)
create mode 100644 clang/test/OpenMP/ompx_extensions_messages.cpp
create mode 100644 clang/test/OpenMP/ompx_taskgraph_ast_print.cpp
create mode 100644 clang/test/OpenMP/ompx_taskgraph_codegen.cpp
diff --git a/clang/include/clang-c/Index.h b/clang/include/clang-c/Index.h
index 64ab3378957c702..03994cb1998b930 100644
--- a/clang/include/clang-c/Index.h
+++ b/clang/include/clang-c/Index.h
@@ -2140,7 +2140,11 @@ enum CXCursorKind {
*/
CXCursor_OMPScopeDirective = 306,
- CXCursor_LastStmt = CXCursor_OMPScopeDirective,
+ /** OpenMP taskgraph directive.
+ */
+ CXCursor_OMPTaskgraphDirective = 307,
+
+ CXCursor_LastStmt = CXCursor_OMPTaskgraphDirective,
/**
* Cursor that represents the translation unit itself.
diff --git a/clang/include/clang/AST/RecursiveASTVisitor.h b/clang/include/clang/AST/RecursiveASTVisitor.h
index 53bc15e1b19f668..6100da39e0273d8 100644
--- a/clang/include/clang/AST/RecursiveASTVisitor.h
+++ b/clang/include/clang/AST/RecursiveASTVisitor.h
@@ -3024,6 +3024,9 @@ DEF_TRAVERSE_STMT(OMPBarrierDirective,
DEF_TRAVERSE_STMT(OMPTaskwaitDirective,
{ TRY_TO(TraverseOMPExecutableDirective(S)); })
+DEF_TRAVERSE_STMT(OMPTaskgraphDirective,
+ { TRY_TO(TraverseOMPExecutableDirective(S)); })
+
DEF_TRAVERSE_STMT(OMPTaskgroupDirective,
{ TRY_TO(TraverseOMPExecutableDirective(S)); })
diff --git a/clang/include/clang/AST/StmtOpenMP.h b/clang/include/clang/AST/StmtOpenMP.h
index 2725747e051e728..4eba370ad7d362d 100644
--- a/clang/include/clang/AST/StmtOpenMP.h
+++ b/clang/include/clang/AST/StmtOpenMP.h
@@ -2729,6 +2729,55 @@ class OMPTaskwaitDirective : public OMPExecutableDirective {
}
};
+/// This represents '#pragma ompx taskgraph' directive.
+/// Available with OMPX extensions.
+///
+/// \code
+/// #pragma ompx taskgraph
+/// \endcode
+///
+class OMPTaskgraphDirective : public OMPExecutableDirective {
+ friend class ASTStmtReader;
+ friend class OMPExecutableDirective;
+ /// Build directive with the given start and end location.
+ ///
+ /// \param StartLoc Starting location of the directive kind.
+ /// \param EndLoc Ending location of the directive.
+ ///
+ OMPTaskgraphDirective(SourceLocation StartLoc, SourceLocation EndLoc)
+ : OMPExecutableDirective(OMPTaskgraphDirectiveClass,
+ llvm::omp::OMPD_taskgraph, StartLoc, EndLoc) {}
+
+ /// Build an empty directive.
+ ///
+ explicit OMPTaskgraphDirective()
+ : OMPExecutableDirective(OMPTaskgraphDirectiveClass,
+ llvm::omp::OMPD_taskgraph, SourceLocation(),
+ SourceLocation()) {}
+
+public:
+ /// Creates directive.
+ ///
+ /// \param C AST context.
+ /// \param StartLoc Starting location of the directive kind.
+ /// \param EndLoc Ending Location of the directive.
+ ///
+ static OMPTaskgraphDirective *
+ Create(const ASTContext &C, SourceLocation StartLoc, SourceLocation EndLoc,
+ ArrayRef<OMPClause *> Clauses, Stmt *AssociatedStmt);
+
+ /// Creates an empty directive.
+ ///
+ /// \param C AST context.
+ ///
+ static OMPTaskgraphDirective *CreateEmpty(const ASTContext &C,
+ unsigned NumClauses, EmptyShell);
+
+ static bool classof(const Stmt *T) {
+ return T->getStmtClass() == OMPTaskgraphDirectiveClass;
+ }
+};
+
/// This represents '#pragma omp taskgroup' directive.
///
/// \code
diff --git a/clang/include/clang/Basic/DiagnosticParseKinds.td b/clang/include/clang/Basic/DiagnosticParseKinds.td
index de180344fcc5c74..fe4d7922f1e9887 100644
--- a/clang/include/clang/Basic/DiagnosticParseKinds.td
+++ b/clang/include/clang/Basic/DiagnosticParseKinds.td
@@ -1176,6 +1176,8 @@ def warn_pragma_ms_fenv_access : Warning<
def warn_pragma_extra_tokens_at_eol : Warning<
"extra tokens at end of '#pragma %0' - ignored">,
InGroup<IgnoredPragmas>;
+def err_omp_extension_without_ompx : Error<
+ "Using extension directive '%0' in #pragma omp instead of #pragma ompx">;
def warn_pragma_expected_comma : Warning<
"expected ',' in '#pragma %0'">, InGroup<IgnoredPragmas>;
def warn_pragma_expected_punc : Warning<
@@ -1406,6 +1408,12 @@ def warn_omp_unknown_assumption_clause_missing_id
def warn_omp_unknown_assumption_clause_without_args
: Warning<"%0 clause should not be followed by arguments; tokens will be ignored">,
InGroup<OpenMPClauses>;
+def warn_omp_extension_directive_not_enabled
+ : Warning<"OpenMP Extensions not enabled. Ignoring OpenMP Extension Directive '#pragma ompx %0'">,
+ InGroup<IgnoredPragmas>;
+def warn_omp_extension_clause_not_enabled
+ : Warning<"OpenMP Extensions not enabled. Ignoring OpenMP Extension Clause '%0'">,
+ InGroup<IgnoredPragmas>;
def note_omp_assumption_clause_continue_here
: Note<"the ignored tokens spans until here">;
def err_omp_declare_target_unexpected_clause: Error<
diff --git a/clang/include/clang/Basic/StmtNodes.td b/clang/include/clang/Basic/StmtNodes.td
index cec301dfca2817b..10f3ed16a06259d 100644
--- a/clang/include/clang/Basic/StmtNodes.td
+++ b/clang/include/clang/Basic/StmtNodes.td
@@ -243,6 +243,7 @@ def OMPTaskDirective : StmtNode<OMPExecutableDirective>;
def OMPTaskyieldDirective : StmtNode<OMPExecutableDirective>;
def OMPBarrierDirective : StmtNode<OMPExecutableDirective>;
def OMPTaskwaitDirective : StmtNode<OMPExecutableDirective>;
+def OMPTaskgraphDirective : StmtNode<OMPExecutableDirective>;
def OMPTaskgroupDirective : StmtNode<OMPExecutableDirective>;
def OMPFlushDirective : StmtNode<OMPExecutableDirective>;
def OMPDepobjDirective : StmtNode<OMPExecutableDirective>;
diff --git a/clang/include/clang/Basic/TokenKinds.def b/clang/include/clang/Basic/TokenKinds.def
index 3ce317d318f9bb6..258f3276cf6b857 100644
--- a/clang/include/clang/Basic/TokenKinds.def
+++ b/clang/include/clang/Basic/TokenKinds.def
@@ -938,10 +938,13 @@ PRAGMA_ANNOTATION(pragma_opencl_extension)
// distinguish between a real pragma and a converted pragma. It is not marked
// as a PRAGMA_ANNOTATION because it doesn't get generated from a #pragma.
ANNOTATION(attr_openmp)
+ANNOTATION(attr_openmp_extension)
// The lexer produces these so that they only take effect when the parser
// handles #pragma omp ... directives.
PRAGMA_ANNOTATION(pragma_openmp)
PRAGMA_ANNOTATION(pragma_openmp_end)
+// For support of OpenMP extensions. These tokens handle #pragma ompx ... directives
+PRAGMA_ANNOTATION(pragma_openmp_extension)
// Annotations for loop pragma directives #pragma clang loop ...
// The lexer produces these so that they only take effect when the parser
diff --git a/clang/include/clang/Parse/Parser.h b/clang/include/clang/Parse/Parser.h
index 30e0352c868637b..5f8448d40aa278d 100644
--- a/clang/include/clang/Parse/Parser.h
+++ b/clang/include/clang/Parse/Parser.h
@@ -175,6 +175,7 @@ class Parser : public CodeCompletionHandler {
std::unique_ptr<PragmaHandler> FPContractHandler;
std::unique_ptr<PragmaHandler> OpenCLExtensionHandler;
std::unique_ptr<PragmaHandler> OpenMPHandler;
+ std::unique_ptr<PragmaHandler> OpenMPXHandler;
std::unique_ptr<PragmaHandler> PCSectionHandler;
std::unique_ptr<PragmaHandler> MSCommentHandler;
std::unique_ptr<PragmaHandler> MSDetectMismatchHandler;
@@ -2895,7 +2896,8 @@ class Parser : public CodeCompletionHandler {
}
void ParseOpenMPAttributeArgs(const IdentifierInfo *AttrName,
- CachedTokens &OpenMPTokens);
+ CachedTokens &OpenMPTokens,
+ bool isOpenMPExtension);
void ParseCXX11AttributeSpecifierInternal(ParsedAttributes &Attrs,
CachedTokens &OpenMPTokens,
@@ -3401,6 +3403,14 @@ class Parser : public CodeCompletionHandler {
const llvm::function_ref<void(CXXScopeSpec &, DeclarationNameInfo)> &
Callback,
bool AllowScopeSpecifier);
+
+ /// Check if clause is extension and extensions are enabled.
+ ///
+ /// \param Kind Kind of the clause
+ /// \param Loc Location of the clause
+ ///
+ bool CheckOpenMPClauseExtension(OpenMPClauseKind Kind, SourceLocation Loc);
+
/// Parses declarative or executable directive.
///
/// \param StmtCtx The context in which we're parsing the directive.
diff --git a/clang/include/clang/Sema/Sema.h b/clang/include/clang/Sema/Sema.h
index 831972495d38ff0..a3445d492729ab4 100644
--- a/clang/include/clang/Sema/Sema.h
+++ b/clang/include/clang/Sema/Sema.h
@@ -11727,6 +11727,10 @@ class Sema final {
StmtResult ActOnOpenMPTaskwaitDirective(ArrayRef<OMPClause *> Clauses,
SourceLocation StartLoc,
SourceLocation EndLoc);
+ /// Called on well-formed '\#pragma ompx taskgraph'.
+ StmtResult ActOnOpenMPTaskgraphDirective(ArrayRef<OMPClause *> Clauses,
+ Stmt *AStmt, SourceLocation StartLoc,
+ SourceLocation EndLoc);
/// Called on well-formed '\#pragma omp taskgroup'.
StmtResult ActOnOpenMPTaskgroupDirective(ArrayRef<OMPClause *> Clauses,
Stmt *AStmt, SourceLocation StartLoc,
diff --git a/clang/include/clang/Serialization/ASTBitCodes.h b/clang/include/clang/Serialization/ASTBitCodes.h
index 5c32fbc079c9a65..3af1b86d98e637d 100644
--- a/clang/include/clang/Serialization/ASTBitCodes.h
+++ b/clang/include/clang/Serialization/ASTBitCodes.h
@@ -1944,6 +1944,7 @@ enum StmtCode {
STMT_OMP_ERROR_DIRECTIVE,
STMT_OMP_BARRIER_DIRECTIVE,
STMT_OMP_TASKWAIT_DIRECTIVE,
+ STMT_OMP_TASKGRAPH_DIRECTIVE,
STMT_OMP_FLUSH_DIRECTIVE,
STMT_OMP_DEPOBJ_DIRECTIVE,
STMT_OMP_SCAN_DIRECTIVE,
diff --git a/clang/lib/AST/StmtOpenMP.cpp b/clang/lib/AST/StmtOpenMP.cpp
index 426b35848cb5c89..1978017a021b725 100644
--- a/clang/lib/AST/StmtOpenMP.cpp
+++ b/clang/lib/AST/StmtOpenMP.cpp
@@ -804,6 +804,21 @@ OMPTaskwaitDirective *OMPTaskwaitDirective::CreateEmpty(const ASTContext &C,
return createEmptyDirective<OMPTaskwaitDirective>(C, NumClauses);
}
+OMPTaskgraphDirective *OMPTaskgraphDirective::Create(
+ const ASTContext &C, SourceLocation StartLoc, SourceLocation EndLoc,
+ ArrayRef<OMPClause *> Clauses, Stmt *AssociatedStmt) {
+ auto *Dir = createDirective<OMPTaskgraphDirective>(
+ C, Clauses, AssociatedStmt, /*NumChildren=*/1, StartLoc, EndLoc);
+ return Dir;
+}
+
+OMPTaskgraphDirective *OMPTaskgraphDirective::CreateEmpty(const ASTContext &C,
+ unsigned NumClauses,
+ EmptyShell) {
+ return createEmptyDirective<OMPTaskgraphDirective>(
+ C, NumClauses, /*HasAssociatedStmt=*/true, /*NumChildren=*/1);
+}
+
OMPTaskgroupDirective *OMPTaskgroupDirective::Create(
const ASTContext &C, SourceLocation StartLoc, SourceLocation EndLoc,
ArrayRef<OMPClause *> Clauses, Stmt *AssociatedStmt, Expr *ReductionRef) {
diff --git a/clang/lib/AST/StmtPrinter.cpp b/clang/lib/AST/StmtPrinter.cpp
index a31aa0cfeeed8de..cd1793edf685ab9 100644
--- a/clang/lib/AST/StmtPrinter.cpp
+++ b/clang/lib/AST/StmtPrinter.cpp
@@ -854,6 +854,11 @@ void StmtPrinter::VisitOMPTaskwaitDirective(OMPTaskwaitDirective *Node) {
PrintOMPExecutableDirective(Node);
}
+void StmtPrinter::VisitOMPTaskgraphDirective(OMPTaskgraphDirective *Node) {
+ Indent() << "#pragma ompx taskgraph";
+ PrintOMPExecutableDirective(Node);
+}
+
void StmtPrinter::VisitOMPErrorDirective(OMPErrorDirective *Node) {
Indent() << "#pragma omp error";
PrintOMPExecutableDirective(Node);
diff --git a/clang/lib/AST/StmtProfile.cpp b/clang/lib/AST/StmtProfile.cpp
index 6510fa369d78eb6..64eb480002831c9 100644
--- a/clang/lib/AST/StmtProfile.cpp
+++ b/clang/lib/AST/StmtProfile.cpp
@@ -1055,6 +1055,10 @@ void StmtProfiler::VisitOMPTaskwaitDirective(const OMPTaskwaitDirective *S) {
VisitOMPExecutableDirective(S);
}
+void StmtProfiler::VisitOMPTaskgraphDirective(const OMPTaskgraphDirective *S) {
+ VisitOMPExecutableDirective(S);
+}
+
void StmtProfiler::VisitOMPErrorDirective(const OMPErrorDirective *S) {
VisitOMPExecutableDirective(S);
}
diff --git a/clang/lib/Basic/OpenMPKinds.cpp b/clang/lib/Basic/OpenMPKinds.cpp
index 86de067da134a0a..05221ac547ee722 100644
--- a/clang/lib/Basic/OpenMPKinds.cpp
+++ b/clang/lib/Basic/OpenMPKinds.cpp
@@ -834,6 +834,9 @@ void clang::getOpenMPCaptureRegions(
CaptureRegions.push_back(OMPD_teams);
CaptureRegions.push_back(OMPD_parallel);
break;
+ case OMPD_taskgraph:
+ CaptureRegions.push_back(OMPD_taskgraph);
+ break;
case OMPD_nothing:
CaptureRegions.push_back(OMPD_nothing);
break;
diff --git a/clang/lib/CodeGen/CGOpenMPRuntime.cpp b/clang/lib/CodeGen/CGOpenMPRuntime.cpp
index 632a44724184925..ff3b532432ada44 100644
--- a/clang/lib/CodeGen/CGOpenMPRuntime.cpp
+++ b/clang/lib/CodeGen/CGOpenMPRuntime.cpp
@@ -60,6 +60,8 @@ class CGOpenMPRegionInfo : public CodeGenFunction::CGCapturedStmtInfo {
ParallelOutlinedRegion,
/// Region with outlined function for standalone 'task' directive.
TaskOutlinedRegion,
+ /// Region with outlined function for standalone 'taskgraph' directive.
+ TaskgraphOutlinedRegion,
/// Region for constructs that do not require function outlining,
/// like 'for', 'sections', 'atomic' etc. directives.
InlinedRegion,
@@ -234,6 +236,26 @@ class CGOpenMPTaskOutlinedRegionInfo final : public CGOpenMPRegionInfo {
const UntiedTaskActionTy &Action;
};
+/// API for captured statement code generation in OpenMP taskgraphs.
+class CGOpenMPTaskgraphRegionInfo final : public CGOpenMPRegionInfo {
+public:
+ CGOpenMPTaskgraphRegionInfo(const CapturedStmt &CS,
+ const RegionCodeGenTy &CodeGen)
+ : CGOpenMPRegionInfo(CS, TaskgraphOutlinedRegion, CodeGen,
+ llvm::omp::OMPD_taskgraph, false) {}
+
+ const VarDecl *getThreadIDVariable() const override { return 0; }
+
+ /// Get the name of the capture helper.
+ StringRef getHelperName() const override { return "taskgraph.omp_outlined."; }
+
+ static bool classof(const CGCapturedStmtInfo *Info) {
+ return CGOpenMPRegionInfo::classof(Info) &&
+ cast<CGOpenMPRegionInfo>(Info)->getRegionKind() ==
+ TaskgraphOutlinedRegion;
+ }
+};
+
/// API for inlined captured statement code generation in OpenMP
/// constructs.
class CGOpenMPInlinedRegionInfo : public CGOpenMPRegionInfo {
@@ -5780,6 +5802,48 @@ void CGOpenMPRuntime::emitTaskwaitCall(CodeGenFunction &CGF, SourceLocation Loc,
Region->emitUntiedSwitch(CGF);
}
+void CGOpenMPRuntime::emitTaskgraphCall(CodeGenFunction &CGF,
+ SourceLocation Loc,
+ const OMPExecutableDirective &D) {
+ if (!CGF.HaveInsertPoint())
+ return;
+
+ // Building kmp_taskgraph_flags_t flags for kmpc_taskgraph. C.f., kmp.h
+ enum {
+ NowaitFlag = 0x1, // Not used yet.
+ ReRecordFlag = 0x2,
+ };
+
+ unsigned Flags = 0;
+
+ CodeGenFunction OutlinedCGF(CGM, true);
+
+ const CapturedStmt *CS = cast<CapturedStmt>(D.getAssociatedStmt());
+
+ auto &&BodyGen = [CS](CodeGenFunction &CGF, PrePostActionTy &) {
+ CGF.EmitStmt(CS->getCapturedStmt());
+ };
+
+ LValue CapStruct = CGF.InitCapturedStruct(*CS);
+ CGOpenMPTaskgraphRegionInfo TaskgraphRegion(*CS, BodyGen);
+ CodeGenFunction::CGCapturedStmtRAII CapInfoRAII(OutlinedCGF,
+ &TaskgraphRegion);
+ llvm::Function *FnT = OutlinedCGF.GenerateCapturedStmtFunction(*CS);
+
+ std::vector<llvm::Value *> Args{
+ emitUpdateLocation(CGF, Loc),
+ getThreadID(CGF, Loc),
+ CGF.Builder.getInt32(Flags),
+ CGF.Builder.getInt32(D.getBeginLoc().getHashValue()),
+ CGF.Builder.CreatePointerBitCastOrAddrSpaceCast(FnT, CGM.VoidPtrTy),
+ CGF.Builder.CreatePointerBitCastOrAddrSpaceCast(
+ CapStruct.getPointer(OutlinedCGF), CGM.VoidPtrTy)};
+
+ CGF.EmitRuntimeCall(OMPBuilder.getOrCreateRuntimeFunction(
+ CGM.getModule(), OMPRTL___kmpc_taskgraph),
+ Args);
+}
+
void CGOpenMPRuntime::emitInlinedDirective(CodeGenFunction &CGF,
OpenMPDirectiveKind InnerKind,
const RegionCodeGenTy &CodeGen,
@@ -6215,6 +6279,7 @@ const Expr *CGOpenMPRuntime::getNumTeamsExprForTargetDirective(
case OMPD_taskyield:
case OMPD_barrier:
case OMPD_taskwait:
+ case OMPD_taskgraph:
case OMPD_taskgroup:
case OMPD_atomic:
case OMPD_flush:
@@ -8963,6 +9028,7 @@ getNestedDistributeDirective(ASTContext &Ctx, const OMPExecutableDirective &D) {
case OMPD_taskyield:
case OMPD_barrier:
case OMPD_taskwait:
+ case OMPD_taskgraph:
case OMPD_taskgroup:
case OMPD_atomic:
case OMPD_flush:
@@ -9823,6 +9889,7 @@ void CGOpenMPRuntime::scanForTargetRegionsFunctions(const Stmt *S,
case OMPD_taskyield:
case OMPD_barrier:
case OMPD_taskwait:
+ case OMPD_taskgraph:
case OMPD_taskgroup:
case OMPD_atomic:
case OMPD_flush:
@@ -10428,6 +10495,7 @@ void CGOpenMPRuntime::emitTargetDataStandAloneCall(
case OMPD_taskyield:
case OMPD_barrier:
case OMPD_taskwait:
+ case OMPD_taskgraph:
case OMPD_taskgroup:
case OMPD_atomic:
case OMPD_flush:
@@ -12165,6 +12233,12 @@ void CGOpenMPSIMDRuntime::emitTaskwaitCall(CodeGenFunction &CGF,
llvm_unreachable("Not supported in SIMD-only mode");
}
+void CGOpenMPSIMDRuntime::emitTaskgraphCall(CodeGenFunction &CGF,
+ SourceLocation Loc,
+ const OMPExecutableDirective &D) {
+ llvm_unreachable("Not supported in SIMD-only mode");
+}
+
void CGOpenMPSIMDRuntime::emitCancellationPointCall(
CodeGenFunction &CGF, SourceLocation Loc,
OpenMPDirectiveKind CancelRegion) {
diff --git a/clang/lib/CodeGen/CGOpenMPRuntime.h b/clang/lib/CodeGen/CGOpenMPRuntime.h
index 0c4ad46e881b9c5..8f27418a8e793c4 100644
--- a/clang/lib/CodeGen/CGOpenMPRuntime.h
+++ b/clang/lib/CodeGen/CGOpenMPRuntime.h
@@ -1341,6 +1341,10 @@ class CGOpenMPRuntime {
virtual void emitTaskwaitCall(CodeGenFunction &CGF, SourceLocation Loc,
const OMPTaskDataTy &Data);
+ /// Emit code for 'taskgraph' directive.
+ virtual void emitTaskgraphCall(CodeGenFunction &CGF, SourceLocation Loc,
+ const OMPExecutableDirective &D);
+
/// Emit code for 'cancellation point' construct.
/// \param CancelRegion Region kind for which the cancellation point must be
/// emitted.
@@ -2146,6 +2150,10 @@ class CGOpenMPSIMDRuntime final : public CGOpenMPRuntime {
void emitTaskwaitCall(CodeGenFunction &CGF, SourceLocation Loc,
const OMPTaskDataTy &Data) override;
+ /// Emit code for 'taskgraph' directive.
+ void emitTaskgraphCall(CodeGenFunction &CGF, SourceLocation Loc,
+ const OMPExecutableDirective &D) override;
+
/// Emit code for 'cancellation point' construct.
/// \param CancelRegion Region kind for which the cancellation point must be
/// emitted.
diff --git a/clang/lib/CodeGen/CGOpenMPRuntimeGPU.cpp b/clang/lib/CodeGen/CGOpenMPRuntimeGPU.cpp
index 370613e75420e23..8435c18a8eed137 100644
--- a/clang/lib/CodeGen/CGOpenMPRuntimeGPU.cpp
+++ b/clang/lib/CodeGen/CGOpenMPRuntimeGPU.cpp
@@ -617,6 +617,7 @@ static bool hasNestedSPMDDirective(ASTContext &Ctx,
case OMPD_taskyield:
case OMPD_barrier:
case OMPD_taskwait:
+ case OMPD_taskgraph:
case OMPD_taskgroup:
case OMPD_atomic:
case OMPD_flush:
@@ -700,6 +701,7 @@ static bool supportsSPMDExecutionMode(ASTContext &Ctx,
case OMPD_taskyield:
case OMPD_barrier:
case OMPD_taskwait:
+ case OMPD_taskgraph:
case OMPD_taskgroup:
case OMPD_atomic:
case OMPD_flush:
diff --git a/clang/lib/CodeGen/CGStmt.cpp b/clang/lib/CodeGen/CGStmt.cpp
index c719df1bfa05036..3d4843560bf1497 100644
--- a/clang/lib/CodeGen/CGStmt.cpp
+++ b/clang/lib/CodeGen/CGStmt.cpp
@@ -266,6 +266,9 @@ void CodeGenFunction::EmitStmt(const Stmt *S, ArrayRef<const Attr *> Attrs) {
case Stmt::OMPTaskwaitDirectiveClass:
EmitOMPTaskwaitDirective(cast<OMPTaskwaitDirective>(*S));
break;
+ case Stmt::OMPTaskgraphDirectiveClass:
+ EmitOMPTaskgraphDirective(cast<OMPTaskgraphDirective>(*S));
+ break;
case Stmt::OMPTaskgroupDirectiveClass:
EmitOMPTaskgroupDirective(cast<OMPTaskgroupDirective>(*S));
break;
diff --git a/clang/lib/CodeGen/CGStmtOpenMP.cpp b/clang/lib/CodeGen/CGStmtOpenMP.cpp
index 3e2ed50a5750254..2db8233417a8c2d 100644
--- a/clang/lib/CodeGen/CGStmtOpenMP.cpp
+++ b/clang/lib/CodeGen/CGStmtOpenMP.cpp
@@ -1350,6 +1350,7 @@ void CodeGenFunction::EmitOMPReductionClauseInit(
case OMPD_error:
case OMPD_barrier:
case OMPD_taskwait:
+ case OMPD_taskgraph:
case OMPD_taskgroup:
case OMPD_flush:
case OMPD_depobj:
@@ -5311,6 +5312,11 @@ void CodeGenFunction::EmitOMPTaskwaitDirective(const OMPTaskwaitDirective &S) {
CGM.getOpenMPRuntime().emitTaskwaitCall(*this, S.getBeginLoc(), Data);
}
+void CodeGenFunction::EmitOMPTaskgraphDirective(
+ const OMPTaskgraphDirective &S) {
+ CGM.getOpenMPRuntime().emitTaskgraphCall(*this, S.getBeginLoc(), S);
+}
+
bool isSupportedByOpenMPIRBuilder(const OMPTaskgroupDirective &T) {
return T.clauses().empty();
}
diff --git a/clang/lib/CodeGen/CodeGenFunction.h b/clang/lib/CodeGen/CodeGenFunction.h
index ee2c4b1e10afba5..581206f6c3d38a6 100644
--- a/clang/lib/CodeGen/CodeGenFunction.h
+++ b/clang/lib/CodeGen/CodeGenFunction.h
@@ -3546,6 +3546,7 @@ class CodeGenFunction : public CodeGenTypeCache {
void EmitOMPErrorDirective(const OMPErrorDirective &S);
void EmitOMPBarrierDirective(const OMPBarrierDirective &S);
void EmitOMPTaskwaitDirective(const OMPTaskwaitDirective &S);
+ void EmitOMPTaskgraphDirective(const OMPTaskgraphDirective &S);
void EmitOMPTaskgroupDirective(const OMPTaskgroupDirective &S);
void EmitOMPFlushDirective(const OMPFlushDirective &S);
void EmitOMPDepobjDirective(const OMPDepobjDirective &S);
diff --git a/clang/lib/Frontend/PrintPreprocessedOutput.cpp b/clang/lib/Frontend/PrintPreprocessedOutput.cpp
index 7f5f6690682300e..37d919eaa778ac9 100644
--- a/clang/lib/Frontend/PrintPreprocessedOutput.cpp
+++ b/clang/lib/Frontend/PrintPreprocessedOutput.cpp
@@ -1012,7 +1012,13 @@ void clang::DoPrintPreprocessedInput(Preprocessor &PP, raw_ostream *OS,
std::unique_ptr<UnknownPragmaHandler> OpenMPHandler(
new UnknownPragmaHandler("#pragma omp", Callbacks,
/*RequireTokenExpansion=*/true));
+
+ std::unique_ptr<UnknownPragmaHandler> OpenMPXHandler(
+ new UnknownPragmaHandler("#pragma ompx", Callbacks,
+ /*RequireTokenExpansion=*/true));
+
PP.AddPragmaHandler("omp", OpenMPHandler.get());
+ PP.AddPragmaHandler("ompx", OpenMPXHandler.get());
PP.addPPCallbacks(std::unique_ptr<PPCallbacks>(Callbacks));
@@ -1049,4 +1055,5 @@ void clang::DoPrintPreprocessedInput(Preprocessor &PP, raw_ostream *OS,
PP.RemovePragmaHandler("GCC", GCCHandler.get());
PP.RemovePragmaHandler("clang", ClangHandler.get());
PP.RemovePragmaHandler("omp", OpenMPHandler.get());
+ PP.RemovePragmaHandler("ompx", OpenMPXHandler.get());
}
diff --git a/clang/lib/Parse/ParseCXXInlineMethods.cpp b/clang/lib/Parse/ParseCXXInlineMethods.cpp
index 573c90a36eeab36..63efe69fa91280d 100644
--- a/clang/lib/Parse/ParseCXXInlineMethods.cpp
+++ b/clang/lib/Parse/ParseCXXInlineMethods.cpp
@@ -807,6 +807,13 @@ void Parser::ParseLexedPragma(LateParsedPragma &LP) {
(void)ParseOpenMPDeclarativeDirectiveWithExtDecl(AS, Attrs);
break;
}
+ case tok::annot_attr_openmp_extension:
+ case tok::annot_pragma_openmp_extension: {
+ AccessSpecifier AS = LP.getAccessSpecifier();
+ ParsedAttributes Attrs(AttrFactory);
+ (void)ParseOpenMPDeclarativeDirectiveWithExtDecl(AS, Attrs);
+ break;
+ }
default:
llvm_unreachable("Unexpected token.");
}
diff --git a/clang/lib/Parse/ParseDecl.cpp b/clang/lib/Parse/ParseDecl.cpp
index 78c3ab72979a007..07ee457d4881c94 100644
--- a/clang/lib/Parse/ParseDecl.cpp
+++ b/clang/lib/Parse/ParseDecl.cpp
@@ -4748,6 +4748,15 @@ void Parser::ParseStructUnionBody(SourceLocation RecordLoc,
continue;
}
+ if (Tok.isOneOf(tok::annot_pragma_openmp_extension,
+ tok::annot_attr_openmp_extension)) {
+ // Result can be ignored, because it must be always empty.
+ AccessSpecifier AS = AS_none;
+ ParsedAttributes Attrs(AttrFactory);
+ (void)ParseOpenMPDeclarativeDirectiveWithExtDecl(AS, Attrs);
+ continue;
+ }
+
if (tok::isPragmaAnnotation(Tok.getKind())) {
Diag(Tok.getLocation(), diag::err_pragma_misplaced_in_decl)
<< DeclSpec::getSpecifierName(
diff --git a/clang/lib/Parse/ParseDeclCXX.cpp b/clang/lib/Parse/ParseDeclCXX.cpp
index 35b1a93a54a6aab..3d2f0a6794f8246 100644
--- a/clang/lib/Parse/ParseDeclCXX.cpp
+++ b/clang/lib/Parse/ParseDeclCXX.cpp
@@ -2786,7 +2786,7 @@ Parser::ParseCXXClassMemberDeclaration(AccessSpecifier AS,
// The next token may be an OpenMP pragma annotation token. That would
// normally be handled from ParseCXXClassMemberDeclarationWithPragmas, but in
// this case, it came from an *attribute* rather than a pragma. Handle it now.
- if (Tok.is(tok::annot_attr_openmp))
+ if (Tok.isOneOf(tok::annot_attr_openmp, tok::annot_attr_openmp_extension))
return ParseOpenMPDeclarativeDirectiveWithExtDecl(AS, DeclAttrs);
if (Tok.is(tok::kw_using)) {
@@ -3427,6 +3427,8 @@ Parser::DeclGroupPtrTy Parser::ParseCXXClassMemberDeclarationWithPragmas(
case tok::annot_attr_openmp:
case tok::annot_pragma_openmp:
+ case tok::annot_attr_openmp_extension:
+ case tok::annot_pragma_openmp_extension:
return ParseOpenMPDeclarativeDirectiveWithExtDecl(
AS, AccessAttrs, /*Delayed=*/true, TagType, TagDecl);
@@ -4307,7 +4309,8 @@ Parser::TryParseCXX11AttributeIdentifier(SourceLocation &Loc,
}
void Parser::ParseOpenMPAttributeArgs(const IdentifierInfo *AttrName,
- CachedTokens &OpenMPTokens) {
+ CachedTokens &OpenMPTokens,
+ bool isOpenMPExtension) {
// Both 'sequence' and 'directive' attributes require arguments, so parse the
// open paren for the argument list.
BalancedDelimiterTracker T(*this, tok::l_paren);
@@ -4322,7 +4325,10 @@ void Parser::ParseOpenMPAttributeArgs(const IdentifierInfo *AttrName,
// pragma directive.
Token OMPBeginTok;
OMPBeginTok.startToken();
- OMPBeginTok.setKind(tok::annot_attr_openmp);
+ if (isOpenMPExtension)
+ OMPBeginTok.setKind(tok::annot_attr_openmp_extension);
+ else
+ OMPBeginTok.setKind(tok::annot_attr_openmp);
OMPBeginTok.setLocation(Tok.getLocation());
OpenMPTokens.push_back(OMPBeginTok);
@@ -4348,8 +4354,12 @@ void Parser::ParseOpenMPAttributeArgs(const IdentifierInfo *AttrName,
// If there is an identifier and it is 'omp', a double colon is required
// followed by the actual identifier we're after.
- if (Ident && Ident->isStr("omp") && !ExpectAndConsume(tok::coloncolon))
+ if (Ident && (Ident->isStr("omp") || Ident->isStr("ompx")) &&
+ !ExpectAndConsume(tok::coloncolon)) {
+ if (Ident->isStr("ompx"))
+ isOpenMPExtension = true;
Ident = TryParseCXX11AttributeIdentifier(IdentLoc);
+ }
// If we failed to find an identifier (scoped or otherwise), or we found
// an unexpected identifier, diagnose.
@@ -4360,7 +4370,7 @@ void Parser::ParseOpenMPAttributeArgs(const IdentifierInfo *AttrName,
}
// We read an identifier. If the identifier is one of the ones we
// expected, we can recurse to parse the args.
- ParseOpenMPAttributeArgs(Ident, OpenMPTokens);
+ ParseOpenMPAttributeArgs(Ident, OpenMPTokens, isOpenMPExtension);
// There may be a comma to signal that we expect another directive in the
// sequence.
@@ -4442,12 +4452,12 @@ bool Parser::ParseCXX11AttributeArgs(
return true;
}
- if (ScopeName && ScopeName->isStr("omp")) {
+ if (ScopeName && (ScopeName->isStr("omp") || ScopeName->isStr("ompx"))) {
Diag(AttrNameLoc, getLangOpts().OpenMP >= 51
? diag::warn_omp51_compat_attributes
: diag::ext_omp_attributes);
- ParseOpenMPAttributeArgs(AttrName, OpenMPTokens);
+ ParseOpenMPAttributeArgs(AttrName, OpenMPTokens, ScopeName->isStr("ompx"));
// We claim that an attribute was parsed and added so that one is not
// created for us by the caller.
diff --git a/clang/lib/Parse/ParseOpenMP.cpp b/clang/lib/Parse/ParseOpenMP.cpp
index 3e7d8274aeefc52..8b5b6132a193132 100644
--- a/clang/lib/Parse/ParseOpenMP.cpp
+++ b/clang/lib/Parse/ParseOpenMP.cpp
@@ -1648,7 +1648,7 @@ void Parser::ParseOpenMPClauses(OpenMPDirectiveKind DKind,
SkipUntil(tok::comma, tok::identifier, tok::annot_pragma_openmp_end,
StopBeforeMatch);
FirstClauses[unsigned(CKind)].setInt(true);
- if (Clause != nullptr)
+ if (Clause != nullptr && CheckOpenMPClauseExtension(CKind, Loc))
Clauses.push_back(Clause);
if (Tok.is(tok::annot_pragma_openmp_end)) {
Actions.EndOpenMPClause();
@@ -2042,8 +2042,14 @@ void Parser::ParseOMPEndDeclareTargetDirective(OpenMPDirectiveKind BeginDKind,
Parser::DeclGroupPtrTy Parser::ParseOpenMPDeclarativeDirectiveWithExtDecl(
AccessSpecifier &AS, ParsedAttributes &Attrs, bool Delayed,
DeclSpec::TST TagType, Decl *Tag) {
- assert(Tok.isOneOf(tok::annot_pragma_openmp, tok::annot_attr_openmp) &&
+ assert(Tok.isOneOf(tok::annot_pragma_openmp, tok::annot_attr_openmp,
+ tok::annot_pragma_openmp_extension,
+ tok::annot_attr_openmp_extension) &&
"Not an OpenMP directive!");
+
+ bool isOmpx = Tok.isOneOf(tok::annot_pragma_openmp_extension,
+ tok::annot_attr_openmp_extension);
+
ParsingOpenMPDirectiveRAII DirScope(*this);
ParenBraceBracketBalancer BalancerRAIIObj(*this);
@@ -2061,7 +2067,9 @@ Parser::DeclGroupPtrTy Parser::ParseOpenMPDeclarativeDirectiveWithExtDecl(
Toks.push_back(Tok);
while (Cnt && Tok.isNot(tok::eof)) {
(void)ConsumeAnyToken();
- if (Tok.isOneOf(tok::annot_pragma_openmp, tok::annot_attr_openmp))
+ if (Tok.isOneOf(tok::annot_pragma_openmp, tok::annot_attr_openmp,
+ tok::annot_pragma_openmp_extension,
+ tok::annot_attr_openmp_extension))
++Cnt;
else if (Tok.is(tok::annot_pragma_openmp_end))
--Cnt;
@@ -2081,6 +2089,24 @@ Parser::DeclGroupPtrTy Parser::ParseOpenMPDeclarativeDirectiveWithExtDecl(
DKind = parseOpenMPDirectiveKind(*this);
}
+ // Check if it is extension directive.
+ // Extension directives must have extension directives
+ // enabled and must use the ompx sentinel
+ if (isExtensionDirective(DKind)) {
+ if (!isOmpx)
+ Diag(Loc, diag::err_omp_extension_without_ompx)
+ << getOpenMPDirectiveName(DKind);
+ else if (!getLangOpts().OpenMPExtensions) {
+ Diag(Loc, diag::warn_omp_extension_directive_not_enabled)
+ << getOpenMPDirectiveName(DKind);
+ ConsumeToken();
+ skipUntilPragmaOpenMPEnd(DKind);
+ if (Tok.is(tok::annot_pragma_openmp_end))
+ ConsumeAnnotationToken();
+ return nullptr;
+ }
+ }
+
switch (DKind) {
case OMPD_threadprivate: {
ConsumeToken();
@@ -2299,7 +2325,8 @@ Parser::DeclGroupPtrTy Parser::ParseOpenMPDeclarativeDirectiveWithExtDecl(
ConsumeAnyToken();
DeclGroupPtrTy Ptr;
- if (Tok.isOneOf(tok::annot_pragma_openmp, tok::annot_attr_openmp)) {
+ if (Tok.isOneOf(tok::annot_pragma_openmp, tok::annot_attr_openmp,
+ tok::annot_pragma_openmp_extension)) {
Ptr = ParseOpenMPDeclarativeDirectiveWithExtDecl(AS, Attrs, Delayed,
TagType, Tag);
} else if (Tok.isNot(tok::r_brace) && !isEofOrEom()) {
@@ -2374,6 +2401,7 @@ Parser::DeclGroupPtrTy Parser::ParseOpenMPDeclarativeDirectiveWithExtDecl(
case OMPD_taskyield:
case OMPD_barrier:
case OMPD_taskwait:
+ case OMPD_taskgraph:
case OMPD_taskgroup:
case OMPD_flush:
case OMPD_depobj:
@@ -2491,8 +2519,13 @@ Parser::DeclGroupPtrTy Parser::ParseOpenMPDeclarativeDirectiveWithExtDecl(
StmtResult Parser::ParseOpenMPDeclarativeOrExecutableDirective(
ParsedStmtContext StmtCtx, bool ReadDirectiveWithinMetadirective) {
if (!ReadDirectiveWithinMetadirective)
- assert(Tok.isOneOf(tok::annot_pragma_openmp, tok::annot_attr_openmp) &&
+ assert(Tok.isOneOf(tok::annot_pragma_openmp, tok::annot_attr_openmp,
+ tok::annot_pragma_openmp_extension,
+ tok::annot_attr_openmp_extension) &&
"Not an OpenMP directive!");
+
+ bool isOmpx = Tok.isOneOf(tok::annot_pragma_openmp_extension,
+ tok::annot_attr_openmp_extension);
ParsingOpenMPDirectiveRAII DirScope(*this);
ParenBraceBracketBalancer BalancerRAIIObj(*this);
SmallVector<OMPClause *, 5> Clauses;
@@ -2516,6 +2549,24 @@ StmtResult Parser::ParseOpenMPDeclarativeOrExecutableDirective(
StmtResult Directive = StmtError();
bool HasAssociatedStatement = true;
+ // Check if it is extension directive.
+ // Extension directives must have extension directives
+ // enabled and must use the ompx sentinel
+ if (isExtensionDirective(DKind)) {
+ if (!isOmpx)
+ Diag(Loc, diag::err_omp_extension_without_ompx)
+ << getOpenMPDirectiveName(DKind);
+ else if (!getLangOpts().OpenMPExtensions) {
+ Diag(Loc, diag::warn_omp_extension_directive_not_enabled)
+ << getOpenMPDirectiveName(DKind);
+ ConsumeToken();
+ skipUntilPragmaOpenMPEnd(DKind);
+ if (Tok.is(tok::annot_pragma_openmp_end))
+ ConsumeAnnotationToken();
+ return Directive;
+ }
+ }
+
switch (DKind) {
case OMPD_nothing:
if ((StmtCtx & ParsedStmtContext::AllowStandaloneOpenMPDirectives) ==
@@ -2798,6 +2849,7 @@ StmtResult Parser::ParseOpenMPDeclarativeOrExecutableDirective(
case OMPD_parallel_master:
case OMPD_parallel_masked:
case OMPD_task:
+ case OMPD_taskgraph:
case OMPD_ordered:
case OMPD_atomic:
case OMPD_target:
@@ -3002,6 +3054,16 @@ StmtResult Parser::ParseOpenMPDeclarativeOrExecutableDirective(
return Directive;
}
+bool Parser::CheckOpenMPClauseExtension(OpenMPClauseKind CKind,
+ SourceLocation Loc) {
+ if (!getLangOpts().OpenMPExtensions && isExtensionClause(CKind)) {
+ Diag(Loc, diag::warn_omp_extension_clause_not_enabled)
+ << getOpenMPClauseName(CKind);
+ return false;
+ }
+ return true;
+}
+
// Parses simple list:
// simple-variable-list:
// '(' id-expression {, id-expression} ')'
@@ -3184,6 +3246,10 @@ OMPClause *Parser::ParseOpenMPClause(OpenMPDirectiveKind DKind,
WrongDirective = true;
}
+ // Check if it is an extension
+ if (!CheckOpenMPClauseExtension(CKind, Tok.getLocation()))
+ ErrorFound = true;
+
switch (CKind) {
case OMPC_final:
case OMPC_num_threads:
diff --git a/clang/lib/Parse/ParsePragma.cpp b/clang/lib/Parse/ParsePragma.cpp
index b3178aef64d72d7..515d7b27169b06d 100644
--- a/clang/lib/Parse/ParsePragma.cpp
+++ b/clang/lib/Parse/ParsePragma.cpp
@@ -178,6 +178,18 @@ struct PragmaOpenMPHandler : public PragmaHandler {
Token &FirstToken) override;
};
+struct PragmaNoOpenMPXHandler : public PragmaHandler {
+ PragmaNoOpenMPXHandler() : PragmaHandler("ompx") {}
+ void HandlePragma(Preprocessor &PP, PragmaIntroducer Introducer,
+ Token &FirstToken) override;
+};
+
+struct PragmaOpenMPXHandler : public PragmaHandler {
+ PragmaOpenMPXHandler() : PragmaHandler("ompx") {}
+ void HandlePragma(Preprocessor &PP, PragmaIntroducer Introducer,
+ Token &FirstToken) override;
+};
+
/// PragmaCommentHandler - "\#pragma comment ...".
struct PragmaCommentHandler : public PragmaHandler {
PragmaCommentHandler(Sema &Actions)
@@ -417,11 +429,15 @@ void Parser::initializePragmaHandlers() {
PP.AddPragmaHandler("OPENCL", FPContractHandler.get());
}
- if (getLangOpts().OpenMP)
+ if (getLangOpts().OpenMP) {
OpenMPHandler = std::make_unique<PragmaOpenMPHandler>();
- else
+ OpenMPXHandler = std::make_unique<PragmaOpenMPXHandler>();
+ } else {
OpenMPHandler = std::make_unique<PragmaNoOpenMPHandler>();
+ OpenMPXHandler = std::make_unique<PragmaNoOpenMPXHandler>();
+ }
PP.AddPragmaHandler(OpenMPHandler.get());
+ PP.AddPragmaHandler(OpenMPXHandler.get());
if (getLangOpts().MicrosoftExt ||
getTargetInfo().getTriple().isOSBinFormatELF()) {
@@ -540,7 +556,9 @@ void Parser::resetPragmaHandlers() {
PP.RemovePragmaHandler("OPENCL", FPContractHandler.get());
}
PP.RemovePragmaHandler(OpenMPHandler.get());
+ PP.RemovePragmaHandler(OpenMPXHandler.get());
OpenMPHandler.reset();
+ OpenMPXHandler.reset();
if (getLangOpts().MicrosoftExt ||
getTargetInfo().getTriple().isOSBinFormatELF()) {
@@ -2663,6 +2681,59 @@ void PragmaOpenMPHandler::HandlePragma(Preprocessor &PP,
/*DisableMacroExpansion=*/false, /*IsReinject=*/false);
}
+/// Handle '#pragma ompx ...' when OpenMP is disabled.
+///
+void PragmaNoOpenMPXHandler::HandlePragma(Preprocessor &PP,
+ PragmaIntroducer Introducer,
+ Token &FirstTok) {
+ if (!PP.getDiagnostics().isIgnored(diag::warn_pragma_omp_ignored,
+ FirstTok.getLocation())) {
+ PP.Diag(FirstTok, diag::warn_pragma_omp_ignored);
+ PP.getDiagnostics().setSeverity(diag::warn_pragma_omp_ignored,
+ diag::Severity::Ignored, SourceLocation());
+ }
+ PP.DiscardUntilEndOfDirective();
+}
+
+/// Handle '#pragma ompx ...' when OpenMP is enabled.
+///
+void PragmaOpenMPXHandler::HandlePragma(Preprocessor &PP,
+ PragmaIntroducer Introducer,
+ Token &FirstTok) {
+ SmallVector<Token, 16> Pragma;
+ Token Tok;
+ Tok.startToken();
+ Tok.setKind(tok::annot_pragma_openmp_extension);
+ Tok.setLocation(Introducer.Loc);
+
+ while (Tok.isNot(tok::eod) && Tok.isNot(tok::eof)) {
+ Pragma.push_back(Tok);
+ PP.Lex(Tok);
+ if (Tok.is(tok::annot_pragma_openmp_extension)) {
+ PP.Diag(Tok, diag::err_omp_unexpected_directive) << 0;
+ unsigned InnerPragmaCnt = 1;
+ while (InnerPragmaCnt != 0) {
+ PP.Lex(Tok);
+ if (Tok.is(tok::annot_pragma_openmp_extension))
+ ++InnerPragmaCnt;
+ else if (Tok.is(tok::annot_pragma_openmp_end))
+ --InnerPragmaCnt;
+ }
+ PP.Lex(Tok);
+ }
+ }
+ SourceLocation EodLoc = Tok.getLocation();
+ Tok.startToken();
+ Tok.setKind(tok::annot_pragma_openmp_end);
+ Tok.setLocation(EodLoc);
+ Pragma.push_back(Tok);
+
+ auto Toks = std::make_unique<Token[]>(Pragma.size());
+ std::copy(Pragma.begin(), Pragma.end(), Toks.get());
+ PP.EnterTokenStream(std::move(Toks), Pragma.size(),
+ /*DisableMacroExpansion=*/false, /*IsReinject=*/false);
+}
+
/// Handle '#pragma pointers_to_members'
// The grammar for this pragma is as follows:
//
diff --git a/clang/lib/Parse/ParseStmt.cpp b/clang/lib/Parse/ParseStmt.cpp
index 2531147c23196ae..0e1220c1594ec14 100644
--- a/clang/lib/Parse/ParseStmt.cpp
+++ b/clang/lib/Parse/ParseStmt.cpp
@@ -466,6 +466,7 @@ StmtResult Parser::ParseStatementOrDeclarationAfterAttributes(
return HandlePragmaCaptured();
case tok::annot_pragma_openmp:
+ case tok::annot_pragma_openmp_extension:
// Prohibit attributes that are not OpenMP attributes, but only before
// processing a #pragma omp clause.
ProhibitAttributes(CXX11Attrs);
diff --git a/clang/lib/Parse/Parser.cpp b/clang/lib/Parse/Parser.cpp
index 176d2149e73184e..80f45c5e984c1d4 100644
--- a/clang/lib/Parse/Parser.cpp
+++ b/clang/lib/Parse/Parser.cpp
@@ -310,6 +310,8 @@ bool Parser::SkipUntil(ArrayRef<tok::TokenKind> Toks, SkipUntilFlags Flags) {
// Ran out of tokens.
return false;
+ case tok::annot_pragma_openmp_extension:
+ case tok::annot_attr_openmp_extension:
case tok::annot_pragma_openmp:
case tok::annot_attr_openmp:
case tok::annot_pragma_openmp_end:
@@ -851,6 +853,10 @@ Parser::ParseExternalDeclaration(ParsedAttributes &Attrs,
AccessSpecifier AS = AS_none;
return ParseOpenMPDeclarativeDirectiveWithExtDecl(AS, Attrs);
}
+ case tok::annot_pragma_openmp_extension: {
+ AccessSpecifier AS = AS_none;
+ return ParseOpenMPDeclarativeDirectiveWithExtDecl(AS, Attrs);
+ }
case tok::annot_pragma_ms_pointers_to_members:
HandlePragmaMSPointersToMembers();
return nullptr;
diff --git a/clang/lib/Sema/SemaExceptionSpec.cpp b/clang/lib/Sema/SemaExceptionSpec.cpp
index 75730ea888afb41..a1da6279633b45b 100644
--- a/clang/lib/Sema/SemaExceptionSpec.cpp
+++ b/clang/lib/Sema/SemaExceptionSpec.cpp
@@ -1501,6 +1501,7 @@ CanThrowResult Sema::canThrow(const Stmt *S) {
case Stmt::OMPScopeDirectiveClass:
case Stmt::OMPTaskDirectiveClass:
case Stmt::OMPTaskgroupDirectiveClass:
+ case Stmt::OMPTaskgraphDirectiveClass:
case Stmt::OMPTaskLoopDirectiveClass:
case Stmt::OMPTaskLoopSimdDirectiveClass:
case Stmt::OMPTaskwaitDirectiveClass:
diff --git a/clang/lib/Sema/SemaOpenMP.cpp b/clang/lib/Sema/SemaOpenMP.cpp
index 1bd34f73e5f7e00..8378c5a7eb9dd9c 100644
--- a/clang/lib/Sema/SemaOpenMP.cpp
+++ b/clang/lib/Sema/SemaOpenMP.cpp
@@ -4322,6 +4322,7 @@ void Sema::ActOnOpenMPRegionStart(OpenMPDirectiveKind DKind, Scope *CurScope) {
case OMPD_for_simd:
case OMPD_sections:
case OMPD_single:
+ case OMPD_taskgraph:
case OMPD_taskgroup:
case OMPD_distribute:
case OMPD_distribute_simd:
@@ -6510,6 +6511,12 @@ StmtResult Sema::ActOnOpenMPExecutableDirective(
"No associated statement allowed for 'omp taskwait' directive");
Res = ActOnOpenMPTaskwaitDirective(ClausesWithImplicit, StartLoc, EndLoc);
break;
+ case OMPD_taskgraph:
+ assert(AStmt != nullptr &&
+ "Associated statement required for 'ompx taskgraph' directive");
+ Res = ActOnOpenMPTaskgraphDirective(ClausesWithImplicit, AStmt, StartLoc,
+ EndLoc);
+ break;
case OMPD_taskgroup:
Res = ActOnOpenMPTaskgroupDirective(ClausesWithImplicit, AStmt, StartLoc,
EndLoc);
@@ -11359,6 +11366,19 @@ StmtResult Sema::ActOnOpenMPTaskwaitDirective(ArrayRef<OMPClause *> Clauses,
return OMPTaskwaitDirective::Create(Context, StartLoc, EndLoc, Clauses);
}
+StmtResult Sema::ActOnOpenMPTaskgraphDirective(ArrayRef<OMPClause *> Clauses,
+ Stmt *AStmt,
+ SourceLocation StartLoc,
+ SourceLocation EndLoc) {
+ if (!AStmt)
+ return StmtError();
+
+ assert(isa<CapturedStmt>(AStmt) && "Captured statement expected");
+
+ return OMPTaskgraphDirective::Create(Context, StartLoc, EndLoc, Clauses,
+ AStmt);
+}
+
StmtResult Sema::ActOnOpenMPTaskgroupDirective(ArrayRef<OMPClause *> Clauses,
Stmt *AStmt,
SourceLocation StartLoc,
@@ -15668,6 +15688,7 @@ static OpenMPDirectiveKind getOpenMPCaptureRegionForClause(
case OMPD_target_teams_distribute:
case OMPD_distribute_parallel_for:
case OMPD_task:
+ case OMPD_taskgraph:
case OMPD_taskloop:
case OMPD_master_taskloop:
case OMPD_masked_taskloop:
@@ -15760,6 +15781,7 @@ static OpenMPDirectiveKind getOpenMPCaptureRegionForClause(
case OMPD_target_teams_distribute_simd:
case OMPD_cancel:
case OMPD_task:
+ case OMPD_taskgraph:
case OMPD_taskloop:
case OMPD_taskloop_simd:
case OMPD_master_taskloop:
@@ -15835,6 +15857,7 @@ static OpenMPDirectiveKind getOpenMPCaptureRegionForClause(
case OMPD_distribute_parallel_for:
case OMPD_distribute_parallel_for_simd:
case OMPD_task:
+ case OMPD_taskgraph:
case OMPD_taskloop:
case OMPD_taskloop_simd:
case OMPD_master_taskloop:
@@ -15933,6 +15956,7 @@ static OpenMPDirectiveKind getOpenMPCaptureRegionForClause(
case OMPD_distribute_parallel_for:
case OMPD_distribute_parallel_for_simd:
case OMPD_task:
+ case OMPD_taskgraph:
case OMPD_taskloop:
case OMPD_taskloop_simd:
case OMPD_master_taskloop:
@@ -16017,6 +16041,7 @@ static OpenMPDirectiveKind getOpenMPCaptureRegionForClause(
// Do not capture schedule-clause expressions.
break;
case OMPD_task:
+ case OMPD_taskgraph:
case OMPD_taskloop:
case OMPD_taskloop_simd:
case OMPD_master_taskloop:
@@ -16113,6 +16138,7 @@ static OpenMPDirectiveKind getOpenMPCaptureRegionForClause(
case OMPD_target_parallel_for_simd:
case OMPD_target_parallel_for:
case OMPD_task:
+ case OMPD_taskgraph:
case OMPD_taskloop:
case OMPD_taskloop_simd:
case OMPD_master_taskloop:
diff --git a/clang/lib/Sema/TreeTransform.h b/clang/lib/Sema/TreeTransform.h
index e24f710fdedd4e2..4433cd9ebe966ce 100644
--- a/clang/lib/Sema/TreeTransform.h
+++ b/clang/lib/Sema/TreeTransform.h
@@ -9078,6 +9078,17 @@ TreeTransform<Derived>::TransformOMPTaskwaitDirective(OMPTaskwaitDirective *D) {
return Res;
}
+template <typename Derived>
+StmtResult TreeTransform<Derived>::TransformOMPTaskgraphDirective(
+ OMPTaskgraphDirective *D) {
+ DeclarationNameInfo DirName;
+ getDerived().getSema().StartOpenMPDSABlock(OMPD_taskgraph, DirName, nullptr,
+ D->getBeginLoc());
+ StmtResult Res = getDerived().TransformOMPExecutableDirective(D);
+ getDerived().getSema().EndOpenMPDSABlock(Res.get());
+ return Res;
+}
+
template <typename Derived>
StmtResult
TreeTransform<Derived>::TransformOMPErrorDirective(OMPErrorDirective *D) {
diff --git a/clang/lib/Serialization/ASTReaderStmt.cpp b/clang/lib/Serialization/ASTReaderStmt.cpp
index d7d0c0e5bb21b47..ee6adb0d9e72b98 100644
--- a/clang/lib/Serialization/ASTReaderStmt.cpp
+++ b/clang/lib/Serialization/ASTReaderStmt.cpp
@@ -2460,6 +2460,11 @@ void ASTStmtReader::VisitOMPTaskwaitDirective(OMPTaskwaitDirective *D) {
VisitOMPExecutableDirective(D);
}
+void ASTStmtReader::VisitOMPTaskgraphDirective(OMPTaskgraphDirective *D) {
+ VisitStmt(D);
+ VisitOMPExecutableDirective(D);
+}
+
void ASTStmtReader::VisitOMPErrorDirective(OMPErrorDirective *D) {
VisitStmt(D);
// The NumClauses field was read in ReadStmtFromStream.
@@ -3421,6 +3426,11 @@ Stmt *ASTReader::ReadStmtFromStream(ModuleFile &F) {
Context, Record[ASTStmtReader::NumStmtFields], Empty);
break;
+ case STMT_OMP_TASKGRAPH_DIRECTIVE:
+ S = OMPTaskgraphDirective::CreateEmpty(
+ Context, Record[ASTStmtReader::NumStmtFields], Empty);
+ break;
+
case STMT_OMP_ERROR_DIRECTIVE:
S = OMPErrorDirective::CreateEmpty(
Context, Record[ASTStmtReader::NumStmtFields], Empty);
diff --git a/clang/lib/Serialization/ASTWriter.cpp b/clang/lib/Serialization/ASTWriter.cpp
index 1e86566d81fbc02..1114123abecfc03 100644
--- a/clang/lib/Serialization/ASTWriter.cpp
+++ b/clang/lib/Serialization/ASTWriter.cpp
@@ -4498,6 +4498,7 @@ void ASTWriter::AddToken(const Token &Tok, RecordDataImpl &Record) {
break;
}
// Some annotation tokens do not use the PtrData field.
+ case tok::annot_pragma_openmp_extension:
case tok::annot_pragma_openmp:
case tok::annot_pragma_openmp_end:
case tok::annot_pragma_unused:
diff --git a/clang/lib/Serialization/ASTWriterStmt.cpp b/clang/lib/Serialization/ASTWriterStmt.cpp
index 59be6828fafabf6..0eb1fa2f26c68d6 100644
--- a/clang/lib/Serialization/ASTWriterStmt.cpp
+++ b/clang/lib/Serialization/ASTWriterStmt.cpp
@@ -2444,6 +2444,12 @@ void ASTStmtWriter::VisitOMPTaskwaitDirective(OMPTaskwaitDirective *D) {
Code = serialization::STMT_OMP_TASKWAIT_DIRECTIVE;
}
+void ASTStmtWriter::VisitOMPTaskgraphDirective(OMPTaskgraphDirective *D) {
+ VisitStmt(D);
+ VisitOMPExecutableDirective(D);
+ Code = serialization::STMT_OMP_TASKGRAPH_DIRECTIVE;
+}
+
void ASTStmtWriter::VisitOMPErrorDirective(OMPErrorDirective *D) {
VisitStmt(D);
Record.push_back(D->getNumClauses());
diff --git a/clang/lib/StaticAnalyzer/Core/ExprEngine.cpp b/clang/lib/StaticAnalyzer/Core/ExprEngine.cpp
index 24e91a22fd6884f..9afeb86aa68eccb 100644
--- a/clang/lib/StaticAnalyzer/Core/ExprEngine.cpp
+++ b/clang/lib/StaticAnalyzer/Core/ExprEngine.cpp
@@ -1768,6 +1768,7 @@ void ExprEngine::Visit(const Stmt *S, ExplodedNode *Pred,
case Stmt::OMPTaskyieldDirectiveClass:
case Stmt::OMPBarrierDirectiveClass:
case Stmt::OMPTaskwaitDirectiveClass:
+ case Stmt::OMPTaskgraphDirectiveClass:
case Stmt::OMPErrorDirectiveClass:
case Stmt::OMPTaskgroupDirectiveClass:
case Stmt::OMPFlushDirectiveClass:
diff --git a/clang/test/OpenMP/ompx_extensions_messages.cpp b/clang/test/OpenMP/ompx_extensions_messages.cpp
new file mode 100644
index 000000000000000..adf0c73aaf271e2
--- /dev/null
+++ b/clang/test/OpenMP/ompx_extensions_messages.cpp
@@ -0,0 +1,12 @@
+// RUN: %clang_cc1 -verify=expected -fopenmp -fno-openmp-extensions -ferror-limit 100 -o - -std=c++11 %s -Wuninitialized
+
+void bad() {
+ #pragma omp taskgraph // expected-error {{Using extension directive 'taskgraph' in #pragma omp instead of #pragma ompx}}
+ {}
+ #pragma ompx taskgraph // expected-warning {{OpenMP Extensions not enabled. Ignoring OpenMP Extension Directive '#pragma ompx taskgraph'}}
+ {}
+ #pragma omp target ompx_attribute() // expected-warning {{OpenMP Extensions not enabled. Ignoring OpenMP Extension Clause 'ompx_attribute'}}
+ {}
+ #pragma omp target ompx_dyn_cgroup_mem(1024) // expected-warning {{OpenMP Extensions not enabled. Ignoring OpenMP Extension Clause 'ompx_dyn_cgroup_mem'}}
+ {}
+}
diff --git a/clang/test/OpenMP/ompx_taskgraph_ast_print.cpp b/clang/test/OpenMP/ompx_taskgraph_ast_print.cpp
new file mode 100644
index 000000000000000..b3a9e2312b9ba13
--- /dev/null
+++ b/clang/test/OpenMP/ompx_taskgraph_ast_print.cpp
@@ -0,0 +1,34 @@
+// RUN: %clang_cc1 -verify -fopenmp -ast-print %s | FileCheck %s
+// RUN: %clang_cc1 -fopenmp -x c++ -std=c++11 -emit-pch -o %t %s
+// RUN: %clang_cc1 -fopenmp -std=c++11 -include-pch %t -fsyntax-only -verify %s -ast-print | FileCheck %s
+
+// RUN: %clang_cc1 -verify -fopenmp-simd -ast-print %s | FileCheck %s
+// RUN: %clang_cc1 -fopenmp-simd -x c++ -std=c++11 -emit-pch -o %t %s
+// RUN: %clang_cc1 -fopenmp-simd -std=c++11 -include-pch %t -fsyntax-only -verify %s -ast-print | FileCheck %s
+// expected-no-diagnostics
+
+#ifndef HEADER
+#define HEADER
+
+int main() {
+// CHECK: #pragma ompx taskgraph
+#pragma ompx taskgraph
+{}
+// CHECK: int foo = 0;
+// CHECK-NEXT: #pragma ompx taskgraph
+ int foo = 0;
+#pragma ompx taskgraph
+{
+ foo++;
+}
+// CHECK: #pragma ompx taskgraph
+ for(int i = 0; i < 10; ++i)
+#pragma ompx taskgraph
+{
+ #pragma omp task
+ foo++;
+}
+ return 0;
+}
+
+#endif
\ No newline at end of file
diff --git a/clang/test/OpenMP/ompx_taskgraph_codegen.cpp b/clang/test/OpenMP/ompx_taskgraph_codegen.cpp
new file mode 100644
index 000000000000000..6ddb64153265b13
--- /dev/null
+++ b/clang/test/OpenMP/ompx_taskgraph_codegen.cpp
@@ -0,0 +1,29 @@
+// RUN: %clang_cc1 -fopenmp -x c++ -triple x86_64-unknown-unknown -emit-llvm -fexceptions -fcxx-exceptions -o - %s | FileCheck %s
+
+// RUN: %clang_cc1 -fopenmp-simd -x c++ -triple x86_64-unknown-unknown -emit-llvm -fexceptions -fcxx-exceptions -o - %s | FileCheck --check-prefix SIMD-ONLY0 %s
+// SIMD-ONLY0-NOT: {{__kmpc|__tgt}}
+
+int main() {
+// CHECK: call i32 @__kmpc_global_thread_num
+// CHECK: call void @__kmpc_taskgraph
+// CHECK: @taskgraph.omp_outlined.
+#pragma ompx taskgraph
+{}
+// CHECK: call void @__kmpc_taskgraph
+// CHECK: @taskgraph.omp_outlined..1
+ int foo = 0;
+#pragma ompx taskgraph
+{
+ foo++;
+}
+// CHECK: call void @__kmpc_taskgraph
+// CHECK: @taskgraph.omp_outlined..2
+ for(int i = 0; i < 10; ++i)
+#pragma ompx taskgraph
+{
+ #pragma omp task
+ foo++;
+}
+ return 0;
+}
+
diff --git a/clang/tools/libclang/CIndex.cpp b/clang/tools/libclang/CIndex.cpp
index df630f66f0b946a..a49f6846bb61af9 100644
--- a/clang/tools/libclang/CIndex.cpp
+++ b/clang/tools/libclang/CIndex.cpp
@@ -5978,6 +5978,8 @@ CXString clang_getCursorKindSpelling(enum CXCursorKind Kind) {
return cxstring::createRef("OMPBarrierDirective");
case CXCursor_OMPTaskwaitDirective:
return cxstring::createRef("OMPTaskwaitDirective");
+ case CXCursor_OMPTaskgraphDirective:
+ return cxstring::createRef("OMPTaskgraphDirective");
case CXCursor_OMPErrorDirective:
return cxstring::createRef("OMPErrorDirective");
case CXCursor_OMPTaskgroupDirective:
diff --git a/clang/tools/libclang/CXCursor.cpp b/clang/tools/libclang/CXCursor.cpp
index fd03c48ba1a42aa..2d87a649f926a39 100644
--- a/clang/tools/libclang/CXCursor.cpp
+++ b/clang/tools/libclang/CXCursor.cpp
@@ -719,6 +719,9 @@ CXCursor cxcursor::MakeCXCursor(const Stmt *S, const Decl *Parent,
case Stmt::OMPTaskwaitDirectiveClass:
K = CXCursor_OMPTaskwaitDirective;
break;
+ case Stmt::OMPTaskgraphDirectiveClass:
+ K = CXCursor_OMPTaskgraphDirective;
+ break;
case Stmt::OMPErrorDirectiveClass:
K = CXCursor_OMPErrorDirective;
break;
diff --git a/llvm/include/llvm/Frontend/Directive/DirectiveBase.td b/llvm/include/llvm/Frontend/Directive/DirectiveBase.td
index 4269a966a988d77..7cb5e93e29e67c4 100644
--- a/llvm/include/llvm/Frontend/Directive/DirectiveBase.td
+++ b/llvm/include/llvm/Frontend/Directive/DirectiveBase.td
@@ -113,6 +113,9 @@ class Clause<string c> {
// Set the prefix as optional.
// `clause([prefix]: value)`
bit isPrefixOptional = true;
+
+ // Is extension (i.e. ompx)
+ bit isExtension = false;
}
// Hold information about clause validity by version.
@@ -154,4 +157,7 @@ class Directive<string d> {
// Set directive used by default when unknown.
bit isDefault = false;
+
+ // Is extension (i.e. ompx)
+ bit isExtension = false;
}
diff --git a/llvm/include/llvm/Frontend/OpenMP/OMP.td b/llvm/include/llvm/Frontend/OpenMP/OMP.td
index f8b3b0c7524979b..e220cb50ecd93df 100644
--- a/llvm/include/llvm/Frontend/OpenMP/OMP.td
+++ b/llvm/include/llvm/Frontend/OpenMP/OMP.td
@@ -440,6 +440,7 @@ def OMPC_Bind : Clause<"bind"> {
def OMPC_OMPX_DynCGroupMem : Clause<"ompx_dyn_cgroup_mem"> {
let clangClass = "OMPXDynCGroupMemClause";
let flangClass = "ScalarIntExpr";
+ let isExtension = true;
}
def OMPC_Doacross : Clause<"doacross"> {
@@ -448,6 +449,7 @@ def OMPC_Doacross : Clause<"doacross"> {
def OMPC_OMPX_Attribute : Clause<"ompx_attribute"> {
let clangClass = "OMPXAttributeClause";
+ let isExtension = true;
}
def OMPC_OMX_Bare : Clause<"ompx_bare"> {
@@ -597,6 +599,9 @@ def OMP_TaskWait : Directive<"taskwait"> {
VersionedClause<OMPC_NoWait, 51>
];
}
+def OMP_TaskGraph : Directive<"taskgraph"> {
+ let isExtension = true;
+}
def OMP_TaskGroup : Directive<"taskgroup"> {
let allowedClauses = [
VersionedClause<OMPC_TaskReduction, 50>,
diff --git a/llvm/include/llvm/Frontend/OpenMP/OMPKinds.def b/llvm/include/llvm/Frontend/OpenMP/OMPKinds.def
index 5215a5a97a0cbdc..303b52f77d8fd50 100644
--- a/llvm/include/llvm/Frontend/OpenMP/OMPKinds.def
+++ b/llvm/include/llvm/Frontend/OpenMP/OMPKinds.def
@@ -351,6 +351,7 @@ __OMP_RTL(__kmpc_omp_task_alloc, false, /* kmp_task_t */ VoidPtr, IdentPtr,
Int32, Int32, SizeTy, SizeTy, TaskRoutineEntryPtr)
__OMP_RTL(__kmpc_omp_task, false, Int32, IdentPtr, Int32,
/* kmp_task_t */ VoidPtr)
+__OMP_RTL(__kmpc_taskgraph, false, Void, IdentPtr, Int32, Int32, Int32, VoidPtr, VoidPtr)
__OMP_RTL(__kmpc_end_taskgroup, false, Void, IdentPtr, Int32)
__OMP_RTL(__kmpc_taskgroup, false, Void, IdentPtr, Int32)
__OMP_RTL(__kmpc_omp_task_begin_if0, false, Void, IdentPtr, Int32,
diff --git a/llvm/include/llvm/TableGen/DirectiveEmitter.h b/llvm/include/llvm/TableGen/DirectiveEmitter.h
index c86018715a48a12..3f0257c5d6c7af7 100644
--- a/llvm/include/llvm/TableGen/DirectiveEmitter.h
+++ b/llvm/include/llvm/TableGen/DirectiveEmitter.h
@@ -93,6 +93,8 @@ class BaseRecord {
bool isDefault() const { return Def->getValueAsBit("isDefault"); }
+ bool isExtension() const { return Def->getValueAsBit("isExtension"); }
+
// Returns the record name.
StringRef getRecordName() const { return Def->getName(); }
diff --git a/llvm/test/TableGen/directive1.td b/llvm/test/TableGen/directive1.td
index b249f2bf5fc6890..00d6c8fa5336c4f 100644
--- a/llvm/test/TableGen/directive1.td
+++ b/llvm/test/TableGen/directive1.td
@@ -98,6 +98,10 @@ def TDL_DirA : Directive<"dira"> {
// CHECK-EMPTY:
// CHECK-NEXT: /// Return true if \p C is a valid clause for \p D in version \p Version.
// CHECK-NEXT: bool isAllowedClauseForDirective(Directive D, Clause C, unsigned Version);
+// CHECK-NEXT: /// Return true if \p C is an extension clause
+// CHECK-NEXT: bool isExtensionClause(Clause C);
+// CHECK-NEXT: /// Return true if \p D is an extension directive
+// CHECK-NEXT: bool isExtensionDirective(Directive D);
// CHECK-EMPTY:
// CHECK-NEXT: AKind getAKind(StringRef);
// CHECK-NEXT: llvm::StringRef getTdlAKindName(AKind);
@@ -341,4 +345,22 @@ def TDL_DirA : Directive<"dira"> {
// IMPL-NEXT: llvm_unreachable("Invalid Tdl Directive kind");
// IMPL-NEXT: }
// IMPL-EMPTY:
+// IMPL-NEXT: bool llvm::tdl::isExtensionClause(Clause C) {
+// IMPL-NEXT: assert(unsigned(C) <= llvm::tdl::Clause_enumSize);
+// IMPL-NEXT: switch (C) {
+// IMPL-NEXT: default:
+// IMPL-NEXT: return false;
+// IMPL-NEXT: }
+// IMPL-NEXT: llvm_unreachable("Invalid Tdl Clause kind");
+// IMPL-NEXT: }
+// IMPL-EMPTY:
+// IMPL-NEXT: bool llvm::tdl::isExtensionDirective(Directive D) {
+// IMPL-NEXT: assert(unsigned(D) <= llvm::tdl::Directive_enumSize);
+// IMPL-NEXT: switch (D) {
+// IMPL-NEXT: default:
+// IMPL-NEXT: return false;
+// IMPL-NEXT: }
+// IMPL-NEXT: llvm_unreachable("Invalid Tdl Directive kind");
+// IMPL-NEXT: }
+// IMPL-EMPTY:
// IMPL-NEXT: #endif // GEN_DIRECTIVES_IMPL
diff --git a/llvm/test/TableGen/directive2.td b/llvm/test/TableGen/directive2.td
index 154d1e86ffb1d66..52215084f1e8f6a 100644
--- a/llvm/test/TableGen/directive2.td
+++ b/llvm/test/TableGen/directive2.td
@@ -73,6 +73,10 @@ def TDL_DirA : Directive<"dira"> {
// CHECK-EMPTY:
// CHECK-NEXT: /// Return true if \p C is a valid clause for \p D in version \p Version.
// CHECK-NEXT: bool isAllowedClauseForDirective(Directive D, Clause C, unsigned Version);
+// CHECK-NEXT: /// Return true if \p C is an extension clause
+// CHECK-NEXT: bool isExtensionClause(Clause C);
+// CHECK-NEXT: /// Return true if \p D is an extension directive
+// CHECK-NEXT: bool isExtensionDirective(Directive D);
// CHECK-EMPTY:
// CHECK-NEXT: } // namespace tdl
// CHECK-NEXT: } // namespace llvm
@@ -271,4 +275,22 @@ def TDL_DirA : Directive<"dira"> {
// IMPL-NEXT: llvm_unreachable("Invalid Tdl Directive kind");
// IMPL-NEXT: }
// IMPL-EMPTY:
+// IMPL-NEXT: bool llvm::tdl::isExtensionClause(Clause C) {
+// IMPL-NEXT: assert(unsigned(C) <= llvm::tdl::Clause_enumSize);
+// IMPL-NEXT: switch (C) {
+// IMPL-NEXT: default:
+// IMPL-NEXT: return false;
+// IMPL-NEXT: }
+// IMPL-NEXT: llvm_unreachable("Invalid Tdl Clause kind");
+// IMPL-NEXT: }
+// IMPL-EMPTY:
+// IMPL-NEXT: bool llvm::tdl::isExtensionDirective(Directive D) {
+// IMPL-NEXT: assert(unsigned(D) <= llvm::tdl::Directive_enumSize);
+// IMPL-NEXT: switch (D) {
+// IMPL-NEXT: default:
+// IMPL-NEXT: return false;
+// IMPL-NEXT: }
+// IMPL-NEXT: llvm_unreachable("Invalid Tdl Directive kind");
+// IMPL-NEXT: }
+// IMPL-EMPTY:
// IMPL-NEXT: #endif // GEN_DIRECTIVES_IMPL
diff --git a/llvm/utils/TableGen/DirectiveEmitter.cpp b/llvm/utils/TableGen/DirectiveEmitter.cpp
index b6aee665f8ee0bb..462ca1d1b6c9013 100644
--- a/llvm/utils/TableGen/DirectiveEmitter.cpp
+++ b/llvm/utils/TableGen/DirectiveEmitter.cpp
@@ -230,6 +230,10 @@ static void EmitDirectivesDecl(RecordKeeper &Records, raw_ostream &OS) {
<< "Version.\n";
OS << "bool isAllowedClauseForDirective(Directive D, "
<< "Clause C, unsigned Version);\n";
+ OS << "/// Return true if \\p C is an extension clause\n";
+ OS << "bool isExtensionClause(Clause C);\n";
+ OS << "/// Return true if \\p D is an extension directive\n";
+ OS << "bool isExtensionDirective(Directive D);\n";
OS << "\n";
if (EnumHelperFuncs.length() > 0) {
OS << EnumHelperFuncs;
@@ -381,6 +385,68 @@ GenerateCaseForVersionedClauses(const std::vector<Record *> &Clauses,
}
}
+// Generate the isExtensionClause function implementation.
+static void GenerateIsExtensionClause(const DirectiveLanguage &DirLang,
+ raw_ostream &OS) {
+ OS << "\n";
+ OS << "bool llvm::" << DirLang.getCppNamespace()
+ << "::isExtensionClause(Clause C) {\n";
+ OS << " assert(unsigned(C) <= llvm::" << DirLang.getCppNamespace()
+ << "::Clause_enumSize);\n";
+
+ OS << " switch (C) {\n";
+
+ bool anyExtensionClause = false;
+ for (const auto &C : DirLang.getClauses()) {
+ Clause Dir{C};
+ if (Dir.isExtension()) {
+ OS << " case " << DirLang.getClausePrefix() << Dir.getFormattedName()
+ << ":\n";
+ anyExtensionClause = true;
+ }
+ }
+ if (anyExtensionClause) {
+ OS << " return true;\n";
+ }
+ OS << " default:\n";
+ OS << " return false;\n";
+ OS << " }\n"; // End of clauses switch
+ OS << " llvm_unreachable(\"Invalid " << DirLang.getName()
+ << " Clause kind\");\n";
+ OS << "}\n"; // End of function isExtensionClause
+}
+
+// Generate the isExtensionDirective function implementation.
+static void GenerateIsExtensionDirective(const DirectiveLanguage &DirLang,
+ raw_ostream &OS) {
+ OS << "\n";
+ OS << "bool llvm::" << DirLang.getCppNamespace()
+ << "::isExtensionDirective(Directive D) {\n";
+ OS << " assert(unsigned(D) <= llvm::" << DirLang.getCppNamespace()
+ << "::Directive_enumSize);\n";
+
+ OS << " switch (D) {\n";
+
+ bool anyExtensionDirective = false;
+ for (const auto &D : DirLang.getDirectives()) {
+ Directive Dir{D};
+ if (Dir.isExtension()) {
+ OS << " case " << DirLang.getDirectivePrefix()
+ << Dir.getFormattedName() << ":\n";
+ anyExtensionDirective = true;
+ }
+ }
+ if (anyExtensionDirective) {
+ OS << " return true;\n";
+ }
+ OS << " default:\n";
+ OS << " return false;\n";
+ OS << " }\n"; // End of clauses switch
+ OS << " llvm_unreachable(\"Invalid " << DirLang.getName()
+ << " Directive kind\");\n";
+ OS << "}\n"; // End of function isExtensionDirective
+}
+
// Generate the isAllowedClauseForDirective function implementation.
static void GenerateIsAllowedClause(const DirectiveLanguage &DirLang,
raw_ostream &OS) {
@@ -876,6 +942,12 @@ void EmitDirectivesBasicImpl(const DirectiveLanguage &DirLang,
// isAllowedClauseForDirective(Directive D, Clause C, unsigned Version)
GenerateIsAllowedClause(DirLang, OS);
+
+ // isExtensionClause
+ GenerateIsExtensionClause(DirLang, OS);
+
+ // isExtensionDirective
+ GenerateIsExtensionDirective(DirLang, OS);
}
// Generate the implemenation section for the enumeration in the directive
diff --git a/openmp/runtime/CMakeLists.txt b/openmp/runtime/CMakeLists.txt
index 8a913989272c4c5..fdf71df8664206d 100644
--- a/openmp/runtime/CMakeLists.txt
+++ b/openmp/runtime/CMakeLists.txt
@@ -352,10 +352,6 @@ if(LIBOMP_OMPD_SUPPORT AND ((NOT LIBOMP_OMPT_SUPPORT) OR (NOT "${CMAKE_SYSTEM_NA
set(LIBOMP_OMPD_SUPPORT FALSE)
endif()
-# OMPX Taskgraph support
-# Whether to build with OMPX Taskgraph (e.g. task record & replay)
-set(LIBOMP_OMPX_TASKGRAPH FALSE CACHE BOOL "OMPX-taskgraph (task record & replay)?")
-
# Error check hwloc support after config-ix has run
if(LIBOMP_USE_HWLOC AND (NOT LIBOMP_HAVE_HWLOC))
libomp_error_say("Hwloc requested but not available")
@@ -425,7 +421,6 @@ if(${OPENMP_STANDALONE_BUILD})
libomp_say("Use Adaptive locks -- ${LIBOMP_USE_ADAPTIVE_LOCKS}")
libomp_say("Use quad precision -- ${LIBOMP_USE_QUAD_PRECISION}")
libomp_say("Use Hwloc library -- ${LIBOMP_USE_HWLOC}")
- libomp_say("Use OMPX-taskgraph -- ${LIBOMP_OMPX_TASKGRAPH}")
endif()
add_subdirectory(src)
diff --git a/openmp/runtime/src/kmp.h b/openmp/runtime/src/kmp.h
index dc759ab1c527703..8b98da6ae12f053 100644
--- a/openmp/runtime/src/kmp.h
+++ b/openmp/runtime/src/kmp.h
@@ -2550,7 +2550,6 @@ typedef struct {
} ed;
} kmp_event_t;
-#if OMPX_TASKGRAPH
// Initial number of allocated nodes while recording
#define INIT_MAPSIZE 50
@@ -2601,11 +2600,10 @@ typedef struct kmp_tdg_info {
extern int __kmp_tdg_dot;
extern kmp_int32 __kmp_max_tdgs;
extern kmp_tdg_info_t **__kmp_global_tdgs;
-extern kmp_int32 __kmp_curr_tdg_idx;
+extern kmp_int32 __kmp_curr_tdg_id;
extern kmp_int32 __kmp_successors_size;
extern std::atomic<kmp_int32> __kmp_tdg_task_id;
extern kmp_int32 __kmp_num_tdg;
-#endif
#ifdef BUILD_TIED_TASK_STACK
@@ -2627,12 +2625,8 @@ typedef struct kmp_task_stack {
typedef struct kmp_tasking_flags { /* Total struct must be exactly 32 bits */
#if __BYTE_ORDER__ == __ORDER_BIG_ENDIAN__
/* Same fields as in the #else branch, but in reverse order */
-#if OMPX_TASKGRAPH
unsigned reserved31 : 6;
unsigned onced : 1;
-#else
- unsigned reserved31 : 7;
-#endif
unsigned native : 1;
unsigned freed : 1;
unsigned complete : 1;
@@ -2681,12 +2675,8 @@ typedef struct kmp_tasking_flags { /* Total struct must be exactly 32 bits */
unsigned complete : 1; /* 1==complete, 0==not complete */
unsigned freed : 1; /* 1==freed, 0==allocated */
unsigned native : 1; /* 1==gcc-compiled task, 0==intel */
-#if OMPX_TASKGRAPH
unsigned onced : 1; /* 1==ran once already, 0==never ran, record & replay purposes */
unsigned reserved31 : 6; /* reserved for library use */
-#else
- unsigned reserved31 : 7; /* reserved for library use */
-#endif
#endif
} kmp_tasking_flags_t;
@@ -2736,10 +2726,8 @@ struct kmp_taskdata { /* aligned during dynamic allocation */
#if OMPT_SUPPORT
ompt_task_info_t ompt_task_info;
#endif
-#if OMPX_TASKGRAPH
bool is_taskgraph = 0; // whether the task is within a TDG
kmp_tdg_info_t *tdg; // used to associate task with a TDG
-#endif
kmp_target_data_t td_target_data;
}; // struct kmp_taskdata
@@ -4299,7 +4287,6 @@ KMP_EXPORT void __kmpc_init_nest_lock_with_hint(ident_t *loc, kmp_int32 gtid,
void **user_lock,
uintptr_t hint);
-#if OMPX_TASKGRAPH
// Taskgraph's Record & Replay mechanism
// __kmp_tdg_is_recording: check whether a given TDG is recording
// status: the tdg's current status
@@ -4312,7 +4299,9 @@ KMP_EXPORT kmp_int32 __kmpc_start_record_task(ident_t *loc, kmp_int32 gtid,
kmp_int32 tdg_id);
KMP_EXPORT void __kmpc_end_record_task(ident_t *loc, kmp_int32 gtid,
kmp_int32 input_flags, kmp_int32 tdg_id);
-#endif
+KMP_EXPORT void __kmpc_taskgraph(ident_t *loc_ref, kmp_int32 gtid,
+ kmp_int32 input_flags, kmp_uint32 tdg_id,
+ void (*entry)(void *), void *args);
/* Interface to fast scalable reduce methods routines */
KMP_EXPORT kmp_int32 __kmpc_reduce_nowait(
diff --git a/openmp/runtime/src/kmp_config.h.cmake b/openmp/runtime/src/kmp_config.h.cmake
index 5f04301c91c60cd..c1aaaaa122ae739 100644
--- a/openmp/runtime/src/kmp_config.h.cmake
+++ b/openmp/runtime/src/kmp_config.h.cmake
@@ -46,8 +46,6 @@
#define OMPT_SUPPORT LIBOMP_OMPT_SUPPORT
#cmakedefine01 LIBOMP_OMPD_SUPPORT
#define OMPD_SUPPORT LIBOMP_OMPD_SUPPORT
-#cmakedefine01 LIBOMP_OMPX_TASKGRAPH
-#define OMPX_TASKGRAPH LIBOMP_OMPX_TASKGRAPH
#cmakedefine01 LIBOMP_PROFILING_SUPPORT
#define OMP_PROFILING_SUPPORT LIBOMP_PROFILING_SUPPORT
#cmakedefine01 LIBOMP_OMPT_OPTIONAL
diff --git a/openmp/runtime/src/kmp_global.cpp b/openmp/runtime/src/kmp_global.cpp
index 48097fb530d1c66..07e58850602a193 100644
--- a/openmp/runtime/src/kmp_global.cpp
+++ b/openmp/runtime/src/kmp_global.cpp
@@ -559,17 +559,15 @@ int __kmp_nesting_mode = 0;
int __kmp_nesting_mode_nlevels = 1;
int *__kmp_nesting_nth_level;
-#if OMPX_TASKGRAPH
// TDG record & replay
int __kmp_tdg_dot = 0;
kmp_int32 __kmp_max_tdgs = 100;
kmp_tdg_info_t **__kmp_global_tdgs = NULL;
-kmp_int32 __kmp_curr_tdg_idx =
+kmp_int32 __kmp_curr_tdg_id =
0; // Id of the current TDG being recorded or executed
kmp_int32 __kmp_num_tdg = 0;
kmp_int32 __kmp_successors_size = 10; // Initial succesor size list for
// recording
std::atomic<kmp_int32> __kmp_tdg_task_id = 0;
-#endif
// end of file //
diff --git a/openmp/runtime/src/kmp_settings.cpp b/openmp/runtime/src/kmp_settings.cpp
index e731bf45e8eee1f..3d546c818fca9f9 100644
--- a/openmp/runtime/src/kmp_settings.cpp
+++ b/openmp/runtime/src/kmp_settings.cpp
@@ -1252,7 +1252,6 @@ static void __kmp_stg_parse_num_threads(char const *name, char const *value,
K_DIAG(1, ("__kmp_dflt_team_nth == %d\n", __kmp_dflt_team_nth));
} // __kmp_stg_parse_num_threads
-#if OMPX_TASKGRAPH
static void __kmp_stg_parse_max_tdgs(char const *name, char const *value,
void *data) {
__kmp_stg_parse_int(name, value, 0, INT_MAX, &__kmp_max_tdgs);
@@ -1272,7 +1271,6 @@ static void __kmp_stg_print_tdg_dot(kmp_str_buf_t *buffer, char const *name,
void *data) {
__kmp_stg_print_bool(buffer, name, __kmp_tdg_dot);
} // __kmp_stg_print_tdg_dot
-#endif
static void __kmp_stg_parse_num_hidden_helper_threads(char const *name,
char const *value,
@@ -5739,11 +5737,9 @@ static kmp_setting_t __kmp_stg_table[] = {
{"LIBOMP_NUM_HIDDEN_HELPER_THREADS",
__kmp_stg_parse_num_hidden_helper_threads,
__kmp_stg_print_num_hidden_helper_threads, NULL, 0, 0},
-#if OMPX_TASKGRAPH
{"KMP_MAX_TDGS", __kmp_stg_parse_max_tdgs, __kmp_std_print_max_tdgs, NULL,
0, 0},
{"KMP_TDG_DOT", __kmp_stg_parse_tdg_dot, __kmp_stg_print_tdg_dot, NULL, 0, 0},
-#endif
#if OMPT_SUPPORT
{"OMP_TOOL", __kmp_stg_parse_omp_tool, __kmp_stg_print_omp_tool, NULL, 0,
diff --git a/openmp/runtime/src/kmp_taskdeps.cpp b/openmp/runtime/src/kmp_taskdeps.cpp
index 3b39f503973635b..ce68dd03efe7508 100644
--- a/openmp/runtime/src/kmp_taskdeps.cpp
+++ b/openmp/runtime/src/kmp_taskdeps.cpp
@@ -218,7 +218,6 @@ static kmp_depnode_list_t *__kmp_add_node(kmp_info_t *thread,
static inline void __kmp_track_dependence(kmp_int32 gtid, kmp_depnode_t *source,
kmp_depnode_t *sink,
kmp_task_t *sink_task) {
-#if OMPX_TASKGRAPH
kmp_taskdata_t *task_source = KMP_TASK_TO_TASKDATA(source->dn.task);
kmp_taskdata_t *task_sink = KMP_TASK_TO_TASKDATA(sink_task);
if (source->dn.task && sink_task) {
@@ -255,7 +254,6 @@ static inline void __kmp_track_dependence(kmp_int32 gtid, kmp_depnode_t *source,
sink_info->npredecessors++;
}
}
-#endif
#ifdef KMP_SUPPORT_GRAPH_OUTPUT
kmp_taskdata_t *task_source = KMP_TASK_TO_TASKDATA(source->dn.task);
// do not use sink->dn.task as that is only filled after the dependences
@@ -294,7 +292,6 @@ __kmp_depnode_link_successor(kmp_int32 gtid, kmp_info_t *thread,
// link node as successor of list elements
for (kmp_depnode_list_t *p = plist; p; p = p->next) {
kmp_depnode_t *dep = p->node;
-#if OMPX_TASKGRAPH
kmp_tdg_status tdg_status = KMP_TDG_NONE;
if (task) {
kmp_taskdata_t *td = KMP_TASK_TO_TASKDATA(task);
@@ -303,13 +300,10 @@ __kmp_depnode_link_successor(kmp_int32 gtid, kmp_info_t *thread,
if (__kmp_tdg_is_recording(tdg_status))
__kmp_track_dependence(gtid, dep, node, task);
}
-#endif
if (dep->dn.task) {
KMP_ACQUIRE_DEPNODE(gtid, dep);
if (dep->dn.task) {
-#if OMPX_TASKGRAPH
if (!(__kmp_tdg_is_recording(tdg_status)) && task)
-#endif
__kmp_track_dependence(gtid, dep, node, task);
dep->dn.successors = __kmp_add_node(thread, dep->dn.successors, node);
KA_TRACE(40, ("__kmp_process_deps: T#%d adding dependence from %p to "
@@ -332,7 +326,6 @@ static inline kmp_int32 __kmp_depnode_link_successor(kmp_int32 gtid,
if (!sink)
return 0;
kmp_int32 npredecessors = 0;
-#if OMPX_TASKGRAPH
kmp_tdg_status tdg_status = KMP_TDG_NONE;
kmp_taskdata_t *td = KMP_TASK_TO_TASKDATA(task);
if (task) {
@@ -341,21 +334,17 @@ static inline kmp_int32 __kmp_depnode_link_successor(kmp_int32 gtid,
if (__kmp_tdg_is_recording(tdg_status) && sink->dn.task)
__kmp_track_dependence(gtid, sink, source, task);
}
-#endif
if (sink->dn.task) {
// synchronously add source to sink' list of successors
KMP_ACQUIRE_DEPNODE(gtid, sink);
if (sink->dn.task) {
-#if OMPX_TASKGRAPH
if (!(__kmp_tdg_is_recording(tdg_status)) && task)
-#endif
__kmp_track_dependence(gtid, sink, source, task);
sink->dn.successors = __kmp_add_node(thread, sink->dn.successors, source);
KA_TRACE(40, ("__kmp_process_deps: T#%d adding dependence from %p to "
"%p\n",
gtid, KMP_TASK_TO_TASKDATA(sink->dn.task),
KMP_TASK_TO_TASKDATA(task)));
-#if OMPX_TASKGRAPH
if (__kmp_tdg_is_recording(tdg_status)) {
kmp_taskdata_t *tdd = KMP_TASK_TO_TASKDATA(sink->dn.task);
if (tdd->is_taskgraph) {
@@ -367,7 +356,6 @@ static inline kmp_int32 __kmp_depnode_link_successor(kmp_int32 gtid,
npredecessors--;
}
}
-#endif
npredecessors++;
}
KMP_RELEASE_DEPNODE(gtid, sink);
@@ -672,7 +660,6 @@ kmp_int32 __kmpc_omp_task_with_deps(ident_t *loc_ref, kmp_int32 gtid,
kmp_info_t *thread = __kmp_threads[gtid];
kmp_taskdata_t *current_task = thread->th.th_current_task;
-#if OMPX_TASKGRAPH
// record TDG with deps
if (new_taskdata->is_taskgraph &&
__kmp_tdg_is_recording(new_taskdata->tdg->tdg_status)) {
@@ -692,7 +679,7 @@ kmp_int32 __kmpc_omp_task_with_deps(ident_t *loc_ref, kmp_int32 gtid,
__kmp_free(old_record);
- for (kmp_int i = old_size; i < new_size; i++) {
+ for (kmp_uint i = old_size; i < new_size; i++) {
kmp_int32 *successorsList = (kmp_int32 *)__kmp_allocate(
__kmp_successors_size * sizeof(kmp_int32));
new_record[i].task = nullptr;
@@ -713,7 +700,6 @@ kmp_int32 __kmpc_omp_task_with_deps(ident_t *loc_ref, kmp_int32 gtid,
new_taskdata->td_parent;
KMP_ATOMIC_INC(&tdg->num_tasks);
}
-#endif
#if OMPT_SUPPORT
if (ompt_enabled.enabled) {
if (!current_task->ompt_task_info.frame.enter_frame.ptr)
diff --git a/openmp/runtime/src/kmp_taskdeps.h b/openmp/runtime/src/kmp_taskdeps.h
index d2ab515158011a1..a5069e1651b9c5c 100644
--- a/openmp/runtime/src/kmp_taskdeps.h
+++ b/openmp/runtime/src/kmp_taskdeps.h
@@ -93,7 +93,6 @@ extern void __kmpc_give_task(kmp_task_t *ptask, kmp_int32 start);
static inline void __kmp_release_deps(kmp_int32 gtid, kmp_taskdata_t *task) {
-#if OMPX_TASKGRAPH
if (task->is_taskgraph && !(__kmp_tdg_is_recording(task->tdg->tdg_status))) {
kmp_node_info_t *TaskInfo = &(task->tdg->record_map[task->td_task_id]);
@@ -107,7 +106,6 @@ static inline void __kmp_release_deps(kmp_int32 gtid, kmp_taskdata_t *task) {
}
return;
}
-#endif
kmp_info_t *thread = __kmp_threads[gtid];
kmp_depnode_t *node = task->td_depnode;
@@ -137,10 +135,8 @@ static inline void __kmp_release_deps(kmp_int32 gtid, kmp_taskdata_t *task) {
gtid, task));
KMP_ACQUIRE_DEPNODE(gtid, node);
-#if OMPX_TASKGRAPH
if (!task->is_taskgraph ||
(task->is_taskgraph && !__kmp_tdg_is_recording(task->tdg->tdg_status)))
-#endif
node->dn.task =
NULL; // mark this task as finished, so no new dependencies are generated
KMP_RELEASE_DEPNODE(gtid, node);
diff --git a/openmp/runtime/src/kmp_tasking.cpp b/openmp/runtime/src/kmp_tasking.cpp
index f90ae9cabab79fa..364b26f6544e675 100644
--- a/openmp/runtime/src/kmp_tasking.cpp
+++ b/openmp/runtime/src/kmp_tasking.cpp
@@ -37,10 +37,9 @@ static void __kmp_alloc_task_deque(kmp_info_t *thread,
static int __kmp_realloc_task_threads_data(kmp_info_t *thread,
kmp_task_team_t *task_team);
static void __kmp_bottom_half_finish_proxy(kmp_int32 gtid, kmp_task_t *ptask);
-#if OMPX_TASKGRAPH
+
static kmp_tdg_info_t *__kmp_find_tdg(kmp_int32 tdg_id);
int __kmp_taskloop_task(int gtid, void *ptask);
-#endif
#ifdef BUILD_TIED_TASK_STACK
@@ -285,11 +284,7 @@ static bool __kmp_task_is_allowed(int gtid, const kmp_int32 is_constrained,
}
// Check mutexinoutset dependencies, acquire locks
kmp_depnode_t *node = tasknew->td_depnode;
-#if OMPX_TASKGRAPH
if (!tasknew->is_taskgraph && UNLIKELY(node && (node->dn.mtx_num_locks > 0))) {
-#else
- if (UNLIKELY(node && (node->dn.mtx_num_locks > 0))) {
-#endif
for (int i = 0; i < node->dn.mtx_num_locks; ++i) {
KMP_DEBUG_ASSERT(node->dn.mtx_locks[i] != NULL);
if (__kmp_test_lock(node->dn.mtx_locks[i], gtid))
@@ -896,17 +891,14 @@ static void __kmp_free_task(kmp_int32 gtid, kmp_taskdata_t *taskdata,
task->data2.priority = 0;
taskdata->td_flags.freed = 1;
-#if OMPX_TASKGRAPH
// do not free tasks in taskgraph
if (!taskdata->is_taskgraph) {
-#endif
// deallocate the taskdata and shared variable blocks associated with this task
#if USE_FAST_MEMORY
__kmp_fast_free(thread, taskdata);
#else /* ! USE_FAST_MEMORY */
__kmp_thread_free(thread, taskdata);
#endif
-#if OMPX_TASKGRAPH
} else {
taskdata->td_flags.complete = 0;
taskdata->td_flags.started = 0;
@@ -922,7 +914,6 @@ static void __kmp_free_task(kmp_int32 gtid, kmp_taskdata_t *taskdata,
// start at one because counts current task and children
KMP_ATOMIC_ST_RLX(&taskdata->td_allocated_child_tasks, 1);
}
-#endif
KA_TRACE(20, ("__kmp_free_task: T#%d freed task %p\n", gtid, taskdata));
}
@@ -1010,10 +1001,8 @@ static bool __kmp_track_children_task(kmp_taskdata_t *taskdata) {
flags.detachable == TASK_DETACHABLE || flags.hidden_helper;
ret = ret ||
KMP_ATOMIC_LD_ACQ(&taskdata->td_parent->td_incomplete_child_tasks) > 0;
-#if OMPX_TASKGRAPH
if (taskdata->td_taskgroup && taskdata->is_taskgraph)
ret = ret || KMP_ATOMIC_LD_ACQ(&taskdata->td_taskgroup->count) > 0;
-#endif
return ret;
}
@@ -1033,10 +1022,8 @@ static void __kmp_task_finish(kmp_int32 gtid, kmp_task_t *task,
kmp_info_t *thread = __kmp_threads[gtid];
kmp_task_team_t *task_team =
thread->th.th_task_team; // might be NULL for serial teams...
-#if OMPX_TASKGRAPH
// to avoid seg fault when we need to access taskdata->td_flags after free when using vanilla taskloop
bool is_taskgraph;
-#endif
#if KMP_DEBUG
kmp_int32 children = 0;
#endif
@@ -1046,9 +1033,7 @@ static void __kmp_task_finish(kmp_int32 gtid, kmp_task_t *task,
KMP_DEBUG_ASSERT(taskdata->td_flags.tasktype == TASK_EXPLICIT);
-#if OMPX_TASKGRAPH
is_taskgraph = taskdata->is_taskgraph;
-#endif
// Pop task from stack if tied
#ifdef BUILD_TIED_TASK_STACK
@@ -1156,9 +1141,7 @@ static void __kmp_task_finish(kmp_int32 gtid, kmp_task_t *task,
if (completed) {
taskdata->td_flags.complete = 1; // mark the task as completed
-#if OMPX_TASKGRAPH
taskdata->td_flags.onced = 1; // mark the task as ran once already
-#endif
#if OMPT_SUPPORT
// This is not a detached task, we are done here
@@ -1175,11 +1158,7 @@ static void __kmp_task_finish(kmp_int32 gtid, kmp_task_t *task,
#endif
KMP_ATOMIC_DEC(&taskdata->td_parent->td_incomplete_child_tasks);
KMP_DEBUG_ASSERT(children >= 0);
-#if OMPX_TASKGRAPH
if (taskdata->td_taskgroup && !taskdata->is_taskgraph)
-#else
- if (taskdata->td_taskgroup)
-#endif
KMP_ATOMIC_DEC(&taskdata->td_taskgroup->count);
} else if (task_team && (task_team->tt.tt_found_proxy_tasks ||
task_team->tt.tt_hidden_helper_task_encountered)) {
@@ -1218,7 +1197,6 @@ static void __kmp_task_finish(kmp_int32 gtid, kmp_task_t *task,
// KMP_DEBUG_ASSERT( resumed_task->td_flags.executing == 0 );
resumed_task->td_flags.executing = 1; // resume previous task
-#if OMPX_TASKGRAPH
if (is_taskgraph && __kmp_track_children_task(taskdata) &&
taskdata->td_taskgroup) {
// TDG: we only release taskgroup barrier here because
@@ -1229,7 +1207,6 @@ static void __kmp_task_finish(kmp_int32 gtid, kmp_task_t *task,
// non-TDG implementation because we never reuse a task(data) structure
KMP_ATOMIC_DEC(&taskdata->td_taskgroup->count);
}
-#endif
KA_TRACE(
10, ("__kmp_task_finish(exit): T#%d finished task %p, resuming task %p\n",
@@ -1347,9 +1324,7 @@ void __kmp_init_implicit_task(ident_t *loc_ref, kmp_info_t *this_thr,
task->td_flags.executing = 1;
task->td_flags.complete = 0;
task->td_flags.freed = 0;
-#if OMPX_TASKGRAPH
task->td_flags.onced = 0;
-#endif
task->td_depnode = NULL;
task->td_last_tied = task;
@@ -1386,9 +1361,7 @@ void __kmp_finish_implicit_task(kmp_info_t *thread) {
if (task->td_dephash) {
int children;
task->td_flags.complete = 1;
-#if OMPX_TASKGRAPH
task->td_flags.onced = 1;
-#endif
children = KMP_ATOMIC_LD_ACQ(&task->td_incomplete_child_tasks);
kmp_tasking_flags_t flags_old = task->td_flags;
if (children == 0 && flags_old.complete == 1) {
@@ -1618,9 +1591,7 @@ kmp_task_t *__kmp_task_alloc(ident_t *loc_ref, kmp_int32 gtid,
taskdata->td_flags.executing = 0;
taskdata->td_flags.complete = 0;
taskdata->td_flags.freed = 0;
-#if OMPX_TASKGRAPH
taskdata->td_flags.onced = 0;
-#endif
KMP_ATOMIC_ST_RLX(&taskdata->td_incomplete_child_tasks, 0);
// start at one because counts current task and children
KMP_ATOMIC_ST_RLX(&taskdata->td_allocated_child_tasks, 1);
@@ -1656,15 +1627,13 @@ kmp_task_t *__kmp_task_alloc(ident_t *loc_ref, kmp_int32 gtid,
}
}
-#if OMPX_TASKGRAPH
- kmp_tdg_info_t *tdg = __kmp_find_tdg(__kmp_curr_tdg_idx);
+ kmp_tdg_info_t *tdg = __kmp_find_tdg(__kmp_curr_tdg_id);
if (tdg && __kmp_tdg_is_recording(tdg->tdg_status) &&
(task_entry != (kmp_routine_entry_t)__kmp_taskloop_task)) {
taskdata->is_taskgraph = 1;
- taskdata->tdg = __kmp_global_tdgs[__kmp_curr_tdg_idx];
+ taskdata->tdg = tdg;
taskdata->td_task_id = KMP_ATOMIC_INC(&__kmp_tdg_task_id);
}
-#endif
KA_TRACE(20, ("__kmp_task_alloc(exit): T#%d created task %p parent=%p\n",
gtid, taskdata, taskdata->td_parent));
@@ -2012,7 +1981,6 @@ kmp_int32 __kmp_omp_task(kmp_int32 gtid, kmp_task_t *new_task,
bool serialize_immediate) {
kmp_taskdata_t *new_taskdata = KMP_TASK_TO_TASKDATA(new_task);
-#if OMPX_TASKGRAPH
if (new_taskdata->is_taskgraph &&
__kmp_tdg_is_recording(new_taskdata->tdg->tdg_status)) {
kmp_tdg_info_t *tdg = new_taskdata->tdg;
@@ -2033,7 +2001,7 @@ kmp_int32 __kmp_omp_task(kmp_int32 gtid, kmp_task_t *new_task,
__kmp_free(old_record);
- for (kmp_int i = old_size; i < new_size; i++) {
+ for (kmp_uint i = old_size; i < new_size; i++) {
kmp_int32 *successorsList = (kmp_int32 *)__kmp_allocate(
__kmp_successors_size * sizeof(kmp_int32));
new_record[i].task = nullptr;
@@ -2057,7 +2025,6 @@ kmp_int32 __kmp_omp_task(kmp_int32 gtid, kmp_task_t *new_task,
KMP_ATOMIC_INC(&tdg->num_tasks);
}
}
-#endif
/* Should we execute the new task or queue it? For now, let's just always try
to queue it. If the queue fills up, then we'll execute it. */
@@ -2574,17 +2541,15 @@ the reduction either does not use omp_orig object, or the omp_orig is accessible
without help of the runtime library.
*/
void *__kmpc_task_reduction_init(int gtid, int num, void *data) {
-#if OMPX_TASKGRAPH
- kmp_tdg_info_t *tdg = __kmp_find_tdg(__kmp_curr_tdg_idx);
+ kmp_tdg_info_t *tdg = __kmp_find_tdg(__kmp_curr_tdg_id);
if (tdg && __kmp_tdg_is_recording(tdg->tdg_status)) {
- kmp_tdg_info_t *this_tdg = __kmp_global_tdgs[__kmp_curr_tdg_idx];
+ kmp_tdg_info_t *this_tdg = __kmp_find_tdg(__kmp_curr_tdg_id);
this_tdg->rec_taskred_data =
__kmp_allocate(sizeof(kmp_task_red_input_t) * num);
this_tdg->rec_num_taskred = num;
KMP_MEMCPY(this_tdg->rec_taskred_data, data,
sizeof(kmp_task_red_input_t) * num);
}
-#endif
return __kmp_task_reduction_init(gtid, num, (kmp_task_red_input_t *)data);
}
@@ -2601,17 +2566,14 @@ Note: this entry supposes the optional compiler-generated initializer routine
has two parameters, pointer to object to be initialized and pointer to omp_orig
*/
void *__kmpc_taskred_init(int gtid, int num, void *data) {
-#if OMPX_TASKGRAPH
- kmp_tdg_info_t *tdg = __kmp_find_tdg(__kmp_curr_tdg_idx);
+ kmp_tdg_info_t *tdg = __kmp_find_tdg(__kmp_curr_tdg_id);
if (tdg && __kmp_tdg_is_recording(tdg->tdg_status)) {
- kmp_tdg_info_t *this_tdg = __kmp_global_tdgs[__kmp_curr_tdg_idx];
- this_tdg->rec_taskred_data =
+ tdg->rec_taskred_data =
__kmp_allocate(sizeof(kmp_task_red_input_t) * num);
- this_tdg->rec_num_taskred = num;
- KMP_MEMCPY(this_tdg->rec_taskred_data, data,
+ tdg->rec_num_taskred = num;
+ KMP_MEMCPY(tdg->rec_taskred_data, data,
sizeof(kmp_task_red_input_t) * num);
}
-#endif
return __kmp_task_reduction_init(gtid, num, (kmp_taskred_input_t *)data);
}
@@ -2658,17 +2620,15 @@ void *__kmpc_task_reduction_get_th_data(int gtid, void *tskgrp, void *data) {
kmp_int32 num = tg->reduce_num_data;
kmp_int32 tid = thread->th.th_info.ds.ds_tid;
-#if OMPX_TASKGRAPH
if ((thread->th.th_current_task->is_taskgraph) &&
(!__kmp_tdg_is_recording(
- __kmp_global_tdgs[__kmp_curr_tdg_idx]->tdg_status))) {
+ __kmp_find_tdg(__kmp_curr_tdg_id)->tdg_status))) {
tg = thread->th.th_current_task->td_taskgroup;
KMP_ASSERT(tg != NULL);
KMP_ASSERT(tg->reduce_data != NULL);
arr = (kmp_taskred_data_t *)(tg->reduce_data);
num = tg->reduce_num_data;
}
-#endif
KMP_ASSERT(data != NULL);
while (tg != NULL) {
@@ -4446,9 +4406,7 @@ static void __kmp_first_top_half_finish_proxy(kmp_taskdata_t *taskdata) {
KMP_DEBUG_ASSERT(taskdata->td_flags.freed == 0);
taskdata->td_flags.complete = 1; // mark the task as completed
-#if OMPX_TASKGRAPH
taskdata->td_flags.onced = 1;
-#endif
if (taskdata->td_taskgroup)
KMP_ATOMIC_DEC(&taskdata->td_taskgroup->count);
@@ -4650,11 +4608,8 @@ void __kmp_fulfill_event(kmp_event_t *event) {
// taskloop_recur: used only when dealing with taskgraph,
// indicating whether we need to update task->td_task_id
// returns: a pointer to the allocated kmp_task_t structure (task).
-kmp_task_t *__kmp_task_dup_alloc(kmp_info_t *thread, kmp_task_t *task_src
-#if OMPX_TASKGRAPH
- , int taskloop_recur
-#endif
-) {
+kmp_task_t *__kmp_task_dup_alloc(kmp_info_t *thread, kmp_task_t *task_src,
+ int taskloop_recur) {
kmp_task_t *task;
kmp_taskdata_t *taskdata;
kmp_taskdata_t *taskdata_src = KMP_TASK_TO_TASKDATA(task_src);
@@ -4682,15 +4637,11 @@ kmp_task_t *__kmp_task_dup_alloc(kmp_info_t *thread, kmp_task_t *task_src
task = KMP_TASKDATA_TO_TASK(taskdata);
// Initialize new task (only specific fields not affected by memcpy)
-#if OMPX_TASKGRAPH
if (!taskdata->is_taskgraph || taskloop_recur)
taskdata->td_task_id = KMP_GEN_TASK_ID();
else if (taskdata->is_taskgraph &&
__kmp_tdg_is_recording(taskdata_src->tdg->tdg_status))
taskdata->td_task_id = KMP_ATOMIC_INC(&__kmp_tdg_task_id);
-#else
- taskdata->td_task_id = KMP_GEN_TASK_ID();
-#endif
if (task->shareds != NULL) { // need setup shareds pointer
shareds_offset = (char *)task_src->shareds - (char *)taskdata_src;
task->shareds = &((char *)taskdata)[shareds_offset];
@@ -4918,11 +4869,7 @@ void __kmp_taskloop_linear(ident_t *loc, int gtid, kmp_task_t *task,
}
}
-#if OMPX_TASKGRAPH
next_task = __kmp_task_dup_alloc(thread, task, /* taskloop_recur */ 0);
-#else
- next_task = __kmp_task_dup_alloc(thread, task); // allocate new task
-#endif
kmp_taskdata_t *next_taskdata = KMP_TASK_TO_TASKDATA(next_task);
kmp_taskloop_bounds_t next_task_bounds =
@@ -5120,12 +5067,8 @@ void __kmp_taskloop_recur(ident_t *loc, int gtid, kmp_task_t *task,
lb1 = ub0 + st;
// create pattern task for 2nd half of the loop
-#if OMPX_TASKGRAPH
next_task = __kmp_task_dup_alloc(thread, task,
/* taskloop_recur */ 1);
-#else
- next_task = __kmp_task_dup_alloc(thread, task); // duplicate the task
-#endif
// adjust lower bound (upper bound is not changed) for the 2nd half
*(kmp_uint64 *)((char *)next_task + lower_offset) = lb1;
if (ptask_dup != NULL) // construct firstprivates, etc.
@@ -5158,11 +5101,9 @@ void __kmp_taskloop_recur(ident_t *loc, int gtid, kmp_task_t *task,
p->codeptr_ra = codeptr_ra;
#endif
-#if OMPX_TASKGRAPH
kmp_taskdata_t *new_task_data = KMP_TASK_TO_TASKDATA(new_task);
new_task_data->tdg = taskdata->tdg;
new_task_data->is_taskgraph = 0;
-#endif
#if OMPT_SUPPORT
// schedule new task with correct return address for OMPT events
@@ -5203,9 +5144,7 @@ static void __kmp_taskloop(ident_t *loc, int gtid, kmp_task_t *task, int if_val,
__kmpc_taskgroup(loc, gtid);
}
-#if OMPX_TASKGRAPH
KMP_ATOMIC_DEC(&__kmp_tdg_task_id);
-#endif
// =========================================================================
// calculate loop parameters
kmp_taskloop_bounds_t task_bounds(task, lb, ub);
@@ -5454,7 +5393,24 @@ bool __kmpc_omp_has_task_team(kmp_int32 gtid) {
return taskdata->td_task_team != NULL;
}
-#if OMPX_TASKGRAPH
+// __kmpc_taskgraph: record or replay taskgraph
+// loc_ref: Location of TDG, not used yet
+// gtid: Global Thread ID of the encountering thread
+// input_flags: Flags associated with the TDG
+// tdg_id: ID of the TDG to record, for now, incremental integer
+// entry: Pointer to the entry function
+// args: Pointer to the function arguments
+void __kmpc_taskgraph(ident_t *loc_ref, kmp_int32 gtid, kmp_int32 input_flags,
+ kmp_uint32 tdg_id, void (*entry)(void *), void *args) {
+ kmp_int32 res = __kmpc_start_record_task(loc_ref, gtid, input_flags, tdg_id);
+ // When res = 1, we either start recording or only execute tasks
+ // without recording. Need to execute entry function in both cases.
+ if (res)
+ entry(args);
+
+ __kmpc_end_record_task(loc_ref, gtid, input_flags, tdg_id);
+}
+
// __kmp_find_tdg: identify a TDG through its ID
// gtid: Global Thread ID
// tdg_id: ID of the TDG
@@ -5469,9 +5425,15 @@ static kmp_tdg_info_t *__kmp_find_tdg(kmp_int32 tdg_id) {
__kmp_global_tdgs = (kmp_tdg_info_t **)__kmp_allocate(
sizeof(kmp_tdg_info_t *) * __kmp_max_tdgs);
- if ((__kmp_global_tdgs[tdg_id]) &&
- (__kmp_global_tdgs[tdg_id]->tdg_status != KMP_TDG_NONE))
- res = __kmp_global_tdgs[tdg_id];
+ for (kmp_int32 i = 0; i < __kmp_num_tdg; ++i) {
+ if ((__kmp_global_tdgs[i]) &&
+ (__kmp_global_tdgs[i]->tdg_id == tdg_id) &&
+ (__kmp_global_tdgs[i]->tdg_status != KMP_TDG_NONE)) {
+ res = __kmp_global_tdgs[i];
+ __kmp_curr_tdg_id = tdg_id;
+ break;
+ }
+ }
return res;
}
@@ -5479,7 +5441,7 @@ static kmp_tdg_info_t *__kmp_find_tdg(kmp_int32 tdg_id) {
// tdg: ID of the TDG
void __kmp_print_tdg_dot(kmp_tdg_info_t *tdg) {
kmp_int32 tdg_id = tdg->tdg_id;
- KA_TRACE(10, ("__kmp_print_tdg_dot(enter): T#%d tdg_id=%d \n", gtid, tdg_id));
+ KA_TRACE(10, ("__kmp_print_tdg_dot(enter): T#%d tdg_id=%d \n", __kmp_get_gtid(), tdg_id));
char file_name[20];
sprintf(file_name, "tdg_%d.dot", tdg_id);
@@ -5505,10 +5467,10 @@ void __kmp_print_tdg_dot(kmp_tdg_info_t *tdg) {
}
}
fprintf(tdg_file, "}");
- KA_TRACE(10, ("__kmp_print_tdg_dot(exit): T#%d tdg_id=%d \n", gtid, tdg_id));
+ KA_TRACE(10, ("__kmp_print_tdg_dot(exit): T#%d tdg_id=%d \n", __kmp_get_gtid(), tdg_id));
}
-// __kmp_start_record: launch the execution of a previous
+// __kmp_exec_tdg: launch the execution of a previous
// recorded TDG
// gtid: Global Thread ID
// tdg: ID of the TDG
@@ -5570,7 +5532,7 @@ static inline void __kmp_start_record(kmp_int32 gtid,
kmp_int32 tdg_id) {
kmp_tdg_info_t *tdg =
(kmp_tdg_info_t *)__kmp_allocate(sizeof(kmp_tdg_info_t));
- __kmp_global_tdgs[__kmp_curr_tdg_idx] = tdg;
+ __kmp_global_tdgs[__kmp_num_tdg-1] = tdg;
// Initializing the TDG structure
tdg->tdg_id = tdg_id;
tdg->map_size = INIT_MAPSIZE;
@@ -5595,7 +5557,7 @@ static inline void __kmp_start_record(kmp_int32 gtid,
KMP_ATOMIC_ST_RLX(&this_record_map[i].npredecessors_counter, 0);
}
- __kmp_global_tdgs[__kmp_curr_tdg_idx]->record_map = this_record_map;
+ tdg->record_map = this_record_map;
}
// __kmpc_start_record_task: Wrapper around __kmp_start_record to mark
@@ -5629,10 +5591,14 @@ kmp_int32 __kmpc_start_record_task(ident_t *loc_ref, kmp_int32 gtid,
__kmp_exec_tdg(gtid, tdg);
res = 0;
} else {
- __kmp_curr_tdg_idx = tdg_id;
- KMP_DEBUG_ASSERT(__kmp_curr_tdg_idx < __kmp_max_tdgs);
- __kmp_start_record(gtid, flags, tdg_id);
- __kmp_num_tdg++;
+ if (__kmp_num_tdg < __kmp_max_tdgs) {
+ __kmp_curr_tdg_id = tdg_id;
+ __kmp_num_tdg++;
+ KMP_DEBUG_ASSERT(__kmp_num_tdg <= __kmp_max_tdgs);
+ __kmp_start_record(gtid, flags, tdg_id);
+ }
+ // if no TDG found, need to execute the task
+ // even not recording
res = 1;
}
KA_TRACE(10, ("__kmpc_start_record_task(exit): T#%d TDG %d starts to %s\n",
@@ -5705,5 +5671,4 @@ void __kmpc_end_record_task(ident_t *loc_ref, kmp_int32 gtid,
KA_TRACE(10, ("__kmpc_end_record_task(exit): T#%d loc=%p finished recording"
" tdg=%d, its status is now READY\n",
gtid, loc_ref, tdg_id));
-}
-#endif
+}
\ No newline at end of file
diff --git a/openmp/runtime/test/CMakeLists.txt b/openmp/runtime/test/CMakeLists.txt
index a7790804542b7ee..05b517fb920fdc7 100644
--- a/openmp/runtime/test/CMakeLists.txt
+++ b/openmp/runtime/test/CMakeLists.txt
@@ -30,7 +30,6 @@ update_test_compiler_features()
pythonize_bool(LIBOMP_USE_HWLOC)
pythonize_bool(LIBOMP_OMPT_SUPPORT)
pythonize_bool(LIBOMP_OMPT_OPTIONAL)
-pythonize_bool(LIBOMP_OMPX_TASKGRAPH)
pythonize_bool(LIBOMP_HAVE_LIBM)
pythonize_bool(LIBOMP_HAVE_LIBATOMIC)
pythonize_bool(OPENMP_STANDALONE_BUILD)
diff --git a/openmp/runtime/test/lit.cfg b/openmp/runtime/test/lit.cfg
index 27ff057c85f60f2..7f7003a24048037 100644
--- a/openmp/runtime/test/lit.cfg
+++ b/openmp/runtime/test/lit.cfg
@@ -105,9 +105,6 @@ if config.has_ompt:
# for callback.h
config.test_flags += " -I " + config.test_source_root + "/ompt"
-if config.has_ompx_taskgraph:
- config.available_features.add("ompx_taskgraph")
-
if 'Linux' in config.operating_system:
config.available_features.add("linux")
diff --git a/openmp/runtime/test/lit.site.cfg.in b/openmp/runtime/test/lit.site.cfg.in
index d6c259280619be9..45a18b480130f6a 100644
--- a/openmp/runtime/test/lit.site.cfg.in
+++ b/openmp/runtime/test/lit.site.cfg.in
@@ -15,7 +15,6 @@ config.operating_system = "@CMAKE_SYSTEM_NAME@"
config.hwloc_library_dir = "@LIBOMP_HWLOC_LIBRARY_DIR@"
config.using_hwloc = @LIBOMP_USE_HWLOC@
config.has_ompt = @LIBOMP_OMPT_SUPPORT@ and @LIBOMP_OMPT_OPTIONAL@
-config.has_ompx_taskgraph = @LIBOMP_OMPX_TASKGRAPH@
config.has_libm = @LIBOMP_HAVE_LIBM@
config.has_libatomic = @LIBOMP_HAVE_LIBATOMIC@
config.is_standalone_build = @OPENMP_STANDALONE_BUILD@
diff --git a/openmp/runtime/test/tasking/omp_record_replay.cpp b/openmp/runtime/test/tasking/omp_record_replay.cpp
index 69ad98003a0d699..54e8090c486ad54 100644
--- a/openmp/runtime/test/tasking/omp_record_replay.cpp
+++ b/openmp/runtime/test/tasking/omp_record_replay.cpp
@@ -1,4 +1,3 @@
-// REQUIRES: ompx_taskgraph
// RUN: %libomp-cxx-compile-and-run
#include <iostream>
#include <cassert>
@@ -29,14 +28,12 @@ int main() {
#pragma omp parallel
#pragma omp single
for (int iter = 0; iter < NT; ++iter) {
- int gtid = __kmpc_global_thread_num(nullptr);
- int res = __kmpc_start_record_task(nullptr, gtid, /* kmp_tdg_flags */ 0, /* tdg_id */0);
- if (res) {
+ #pragma ompx taskgraph
+ {
num_tasks++;
#pragma omp task
func(&num_exec);
}
- __kmpc_end_record_task(nullptr, gtid, /* kmp_tdg_flags */0, /* tdg_id */0);
}
assert(num_tasks==1);
diff --git a/openmp/runtime/test/tasking/omp_record_replay_deps.cpp b/openmp/runtime/test/tasking/omp_record_replay_deps.cpp
index 9b6b370b30efc15..c370ad34b5528bf 100644
--- a/openmp/runtime/test/tasking/omp_record_replay_deps.cpp
+++ b/openmp/runtime/test/tasking/omp_record_replay_deps.cpp
@@ -1,4 +1,3 @@
-// REQUIRES: ompx_taskgraph
// RUN: %libomp-cxx-compile-and-run
#include <iostream>
#include <cassert>
@@ -43,9 +42,8 @@ int main() {
#pragma omp parallel
#pragma omp single
for (int iter = 0; iter < NT; ++iter) {
- int gtid = __kmpc_global_thread_num(nullptr);
- int res = __kmpc_start_record_task(nullptr, gtid, /* kmp_tdg_flags */0, /* tdg_id */0);
- if (res) {
+ #pragma ompx taskgraph
+ {
#pragma omp task depend(out:y)
add();
#pragma omp task depend(out:x)
@@ -53,7 +51,6 @@ int main() {
#pragma omp task depend(in:x,y)
mult();
}
- __kmpc_end_record_task(nullptr, gtid, /* kmp_tdg_flags */0, /* tdg_id */0);
}
assert(val==0);
diff --git a/openmp/runtime/test/tasking/omp_record_replay_multiTDGs.cpp b/openmp/runtime/test/tasking/omp_record_replay_multiTDGs.cpp
index 03252843689c401..282625ddb47826c 100644
--- a/openmp/runtime/test/tasking/omp_record_replay_multiTDGs.cpp
+++ b/openmp/runtime/test/tasking/omp_record_replay_multiTDGs.cpp
@@ -1,4 +1,3 @@
-// REQUIRES: ompx_taskgraph
// RUN: %libomp-cxx-compile-and-run
#include <iostream>
#include <cassert>
@@ -42,9 +41,8 @@ int main() {
#pragma omp parallel
#pragma omp single
for (int iter = 0; iter < NT; ++iter) {
- int gtid = __kmpc_global_thread_num(nullptr);
- int res = __kmpc_start_record_task(nullptr, gtid, /* kmp_tdg_flags */ 0, /* tdg_id */0);
- if (res) {
+ #pragma ompx taskgraph
+ {
num_tasks++;
#pragma omp task depend(out:y)
add();
@@ -53,9 +51,8 @@ int main() {
#pragma omp task depend(in:x,y)
mult();
}
- __kmpc_end_record_task(nullptr, gtid, /* kmp_tdg_flags */0, /* tdg_id */0);
- res = __kmpc_start_record_task(nullptr, gtid, /* kmp_tdg_flags */ 0, /* tdg_id */1);
- if (res) {
+ #pragma ompx taskgraph
+ {
num_tasks++;
#pragma omp task depend(out:y)
add();
@@ -64,7 +61,6 @@ int main() {
#pragma omp task depend(in:x,y)
mult();
}
- __kmpc_end_record_task(nullptr, gtid, /* kmp_tdg_flags */0, /* tdg_id */1);
}
assert(num_tasks==2);
diff --git a/openmp/runtime/test/tasking/omp_record_replay_print_dot.cpp b/openmp/runtime/test/tasking/omp_record_replay_print_dot.cpp
index 2fe55f081542903..522068c359e6a59 100644
--- a/openmp/runtime/test/tasking/omp_record_replay_print_dot.cpp
+++ b/openmp/runtime/test/tasking/omp_record_replay_print_dot.cpp
@@ -1,4 +1,3 @@
-// REQUIRES: ompx_taskgraph
// RUN: %libomp-cxx-compile-and-run
#include <iostream>
#include <fstream>
@@ -26,7 +25,7 @@ void func(int *num_exec) {
std::string tdg_string= "digraph TDG {\n"
" compound=true\n"
" subgraph cluster {\n"
-" label=TDG_0\n"
+" label=TDG_33263\n"
" 0[style=bold]\n"
" 1[style=bold]\n"
" 2[style=bold]\n"
@@ -47,9 +46,8 @@ int main() {
#pragma omp parallel
#pragma omp single
{
- int gtid = __kmpc_global_thread_num(nullptr);
- int res = __kmpc_start_record_task(nullptr, gtid, /* kmp_tdg_flags */ 0, /* tdg_id */ 0);
- if (res) {
+ #pragma ompx taskgraph
+ {
#pragma omp task depend(out : x)
func(&num_exec);
#pragma omp task depend(in : x) depend(out : y)
@@ -59,13 +57,11 @@ int main() {
#pragma omp task depend(in : y)
func(&num_exec);
}
-
- __kmpc_end_record_task(nullptr, gtid, /* kmp_tdg_flags */ 0, /* tdg_id */ 0);
}
assert(num_exec == 4);
- std::ifstream tdg_file("tdg_0.dot");
+ std::ifstream tdg_file("tdg_33263.dot");
assert(tdg_file.is_open());
std::stringstream tdg_file_stream;
diff --git a/openmp/runtime/test/tasking/omp_record_replay_taskloop.cpp b/openmp/runtime/test/tasking/omp_record_replay_taskloop.cpp
index 3d88faeeb28eea1..dd814ff36e9e7a1 100644
--- a/openmp/runtime/test/tasking/omp_record_replay_taskloop.cpp
+++ b/openmp/runtime/test/tasking/omp_record_replay_taskloop.cpp
@@ -1,4 +1,3 @@
-// REQUIRES: ompx_taskgraph
// RUN: %libomp-cxx-compile-and-run
#include <iostream>
#include <cassert>
@@ -30,16 +29,14 @@ int main() {
#pragma omp parallel
#pragma omp single
for (int iter = 0; iter < NT; ++iter) {
- int gtid = __kmpc_global_thread_num(nullptr);
- int res = __kmpc_start_record_task(nullptr, gtid, /* kmp_tdg_flags */0, /* tdg_id */0);
- if (res) {
+ #pragma ompx taskgraph
+ {
num_tasks++;
#pragma omp taskloop reduction(+:sum) num_tasks(4096)
for (int i = 0; i < N; ++i) {
sum += array[i];
}
}
- __kmpc_end_record_task(nullptr, gtid, /* kmp_tdg_flags */0, /* tdg_id */0);
}
assert(sum==N*NT);
assert(num_tasks==1);
>From ce5588ae5edc8275c34cd28f1562271f1761ba03 Mon Sep 17 00:00:00 2001
From: Adrian Munera <adrian.munera at bsc.es>
Date: Tue, 26 Sep 2023 14:19:01 +0000
Subject: [PATCH 2/3] fixup! clean ompx code and address minor issues
---
clang/include/clang/AST/StmtOpenMP.h | 2 +-
clang/include/clang/Basic/DiagnosticParseKinds.td | 6 +++---
clang/lib/Parse/ParseCXXInlineMethods.cpp | 7 +------
clang/lib/Parse/ParseDecl.cpp | 11 ++---------
clang/lib/Parse/ParseOpenMP.cpp | 8 ++++----
clang/lib/Parse/Parser.cpp | 5 +----
clang/test/OpenMP/ompx_extensions_messages.cpp | 2 +-
7 files changed, 13 insertions(+), 28 deletions(-)
diff --git a/clang/include/clang/AST/StmtOpenMP.h b/clang/include/clang/AST/StmtOpenMP.h
index 4eba370ad7d362d..66fe05b6b3b8ccd 100644
--- a/clang/include/clang/AST/StmtOpenMP.h
+++ b/clang/include/clang/AST/StmtOpenMP.h
@@ -2736,7 +2736,7 @@ class OMPTaskwaitDirective : public OMPExecutableDirective {
/// #pragma ompx taskgraph
/// \endcode
///
-class OMPTaskgraphDirective : public OMPExecutableDirective {
+class OMPTaskgraphDirective final : public OMPExecutableDirective {
friend class ASTStmtReader;
friend class OMPExecutableDirective;
/// Build directive with the given start and end location.
diff --git a/clang/include/clang/Basic/DiagnosticParseKinds.td b/clang/include/clang/Basic/DiagnosticParseKinds.td
index fe4d7922f1e9887..1fdf366b9b07841 100644
--- a/clang/include/clang/Basic/DiagnosticParseKinds.td
+++ b/clang/include/clang/Basic/DiagnosticParseKinds.td
@@ -1177,7 +1177,7 @@ def warn_pragma_extra_tokens_at_eol : Warning<
"extra tokens at end of '#pragma %0' - ignored">,
InGroup<IgnoredPragmas>;
def err_omp_extension_without_ompx : Error<
- "Using extension directive '%0' in #pragma omp instead of #pragma ompx">;
+ "Expected extension directive '%0' in #pragma omp instead of #pragma ompx">;
def warn_pragma_expected_comma : Warning<
"expected ',' in '#pragma %0'">, InGroup<IgnoredPragmas>;
def warn_pragma_expected_punc : Warning<
@@ -1410,10 +1410,10 @@ def warn_omp_unknown_assumption_clause_without_args
InGroup<OpenMPClauses>;
def warn_omp_extension_directive_not_enabled
: Warning<"OpenMP Extensions not enabled. Ignoring OpenMP Extension Directive '#pragma ompx %0'">,
- InGroup<IgnoredPragmas>;
+ InGroup<OpenMPClauses>;
def warn_omp_extension_clause_not_enabled
: Warning<"OpenMP Extensions not enabled. Ignoring OpenMP Extension Clause '%0'">,
- InGroup<IgnoredPragmas>;
+ InGroup<OpenMPClauses>;
def note_omp_assumption_clause_continue_here
: Note<"the ignored tokens spans until here">;
def err_omp_declare_target_unexpected_clause: Error<
diff --git a/clang/lib/Parse/ParseCXXInlineMethods.cpp b/clang/lib/Parse/ParseCXXInlineMethods.cpp
index 63efe69fa91280d..22d1a46f6f2dbc5 100644
--- a/clang/lib/Parse/ParseCXXInlineMethods.cpp
+++ b/clang/lib/Parse/ParseCXXInlineMethods.cpp
@@ -801,12 +801,7 @@ void Parser::ParseLexedPragma(LateParsedPragma &LP) {
assert(Tok.isAnnotation() && "Expected annotation token.");
switch (Tok.getKind()) {
case tok::annot_attr_openmp:
- case tok::annot_pragma_openmp: {
- AccessSpecifier AS = LP.getAccessSpecifier();
- ParsedAttributes Attrs(AttrFactory);
- (void)ParseOpenMPDeclarativeDirectiveWithExtDecl(AS, Attrs);
- break;
- }
+ case tok::annot_pragma_openmp:
case tok::annot_attr_openmp_extension:
case tok::annot_pragma_openmp_extension: {
AccessSpecifier AS = LP.getAccessSpecifier();
diff --git a/clang/lib/Parse/ParseDecl.cpp b/clang/lib/Parse/ParseDecl.cpp
index 07ee457d4881c94..72ffbaec92694cf 100644
--- a/clang/lib/Parse/ParseDecl.cpp
+++ b/clang/lib/Parse/ParseDecl.cpp
@@ -4740,15 +4740,8 @@ void Parser::ParseStructUnionBody(SourceLocation RecordLoc,
continue;
}
- if (Tok.isOneOf(tok::annot_pragma_openmp, tok::annot_attr_openmp)) {
- // Result can be ignored, because it must be always empty.
- AccessSpecifier AS = AS_none;
- ParsedAttributes Attrs(AttrFactory);
- (void)ParseOpenMPDeclarativeDirectiveWithExtDecl(AS, Attrs);
- continue;
- }
-
- if (Tok.isOneOf(tok::annot_pragma_openmp_extension,
+ if (Tok.isOneOf(tok::annot_pragma_openmp, tok::annot_attr_openmp,
+ tok::annot_pragma_openmp_extension,
tok::annot_attr_openmp_extension)) {
// Result can be ignored, because it must be always empty.
AccessSpecifier AS = AS_none;
diff --git a/clang/lib/Parse/ParseOpenMP.cpp b/clang/lib/Parse/ParseOpenMP.cpp
index 8b5b6132a193132..8a879f6eacf1e37 100644
--- a/clang/lib/Parse/ParseOpenMP.cpp
+++ b/clang/lib/Parse/ParseOpenMP.cpp
@@ -2093,10 +2093,10 @@ Parser::DeclGroupPtrTy Parser::ParseOpenMPDeclarativeDirectiveWithExtDecl(
// Extension directives must have extension directives
// enabled and must use the ompx sentinel
if (isExtensionDirective(DKind)) {
- if (!isOmpx)
+ if (!isOmpx) {
Diag(Loc, diag::err_omp_extension_without_ompx)
<< getOpenMPDirectiveName(DKind);
- else if (!getLangOpts().OpenMPExtensions) {
+ } else if (!getLangOpts().OpenMPExtensions) {
Diag(Loc, diag::warn_omp_extension_directive_not_enabled)
<< getOpenMPDirectiveName(DKind);
ConsumeToken();
@@ -2553,10 +2553,10 @@ StmtResult Parser::ParseOpenMPDeclarativeOrExecutableDirective(
// Extension directives must have extension directives
// enabled and must use the ompx sentinel
if (isExtensionDirective(DKind)) {
- if (!isOmpx)
+ if (!isOmpx) {
Diag(Loc, diag::err_omp_extension_without_ompx)
<< getOpenMPDirectiveName(DKind);
- else if (!getLangOpts().OpenMPExtensions) {
+ } else if (!getLangOpts().OpenMPExtensions) {
Diag(Loc, diag::warn_omp_extension_directive_not_enabled)
<< getOpenMPDirectiveName(DKind);
ConsumeToken();
diff --git a/clang/lib/Parse/Parser.cpp b/clang/lib/Parse/Parser.cpp
index 80f45c5e984c1d4..130638c30333081 100644
--- a/clang/lib/Parse/Parser.cpp
+++ b/clang/lib/Parse/Parser.cpp
@@ -849,10 +849,7 @@ Parser::ParseExternalDeclaration(ParsedAttributes &Attrs,
HandlePragmaOpenCLExtension();
return nullptr;
case tok::annot_attr_openmp:
- case tok::annot_pragma_openmp: {
- AccessSpecifier AS = AS_none;
- return ParseOpenMPDeclarativeDirectiveWithExtDecl(AS, Attrs);
- }
+ case tok::annot_pragma_openmp:
case tok::annot_pragma_openmp_extension: {
AccessSpecifier AS = AS_none;
return ParseOpenMPDeclarativeDirectiveWithExtDecl(AS, Attrs);
diff --git a/clang/test/OpenMP/ompx_extensions_messages.cpp b/clang/test/OpenMP/ompx_extensions_messages.cpp
index adf0c73aaf271e2..195e2e7cb4b9022 100644
--- a/clang/test/OpenMP/ompx_extensions_messages.cpp
+++ b/clang/test/OpenMP/ompx_extensions_messages.cpp
@@ -1,7 +1,7 @@
// RUN: %clang_cc1 -verify=expected -fopenmp -fno-openmp-extensions -ferror-limit 100 -o - -std=c++11 %s -Wuninitialized
void bad() {
- #pragma omp taskgraph // expected-error {{Using extension directive 'taskgraph' in #pragma omp instead of #pragma ompx}}
+ #pragma omp taskgraph // expected-error {{Expected extension directive 'taskgraph' in #pragma omp instead of #pragma ompx}}
{}
#pragma ompx taskgraph // expected-warning {{OpenMP Extensions not enabled. Ignoring OpenMP Extension Directive '#pragma ompx taskgraph'}}
{}
>From ac328771e1afd0cd42f5ebc698f29be866a9a07d Mon Sep 17 00:00:00 2001
From: Adrian Munera <adrian.munera at bsc.es>
Date: Sun, 5 Nov 2023 15:18:20 +0000
Subject: [PATCH 3/3] Revert OpenMP runtime changes
---
openmp/runtime/CMakeLists.txt | 5 +
openmp/runtime/src/kmp.h | 19 ++-
openmp/runtime/src/kmp_config.h.cmake | 2 +
openmp/runtime/src/kmp_global.cpp | 4 +-
openmp/runtime/src/kmp_settings.cpp | 4 +
openmp/runtime/src/kmp_taskdeps.cpp | 16 +-
openmp/runtime/src/kmp_taskdeps.h | 4 +
openmp/runtime/src/kmp_tasking.cpp | 143 +++++++++++-------
openmp/runtime/test/CMakeLists.txt | 1 +
openmp/runtime/test/lit.cfg | 3 +
openmp/runtime/test/lit.site.cfg.in | 1 +
.../test/tasking/omp_record_replay.cpp | 7 +-
.../test/tasking/omp_record_replay_deps.cpp | 7 +-
.../tasking/omp_record_replay_multiTDGs.cpp | 12 +-
.../tasking/omp_record_replay_print_dot.cpp | 12 +-
.../tasking/omp_record_replay_taskloop.cpp | 7 +-
16 files changed, 173 insertions(+), 74 deletions(-)
diff --git a/openmp/runtime/CMakeLists.txt b/openmp/runtime/CMakeLists.txt
index fdf71df8664206d..8a913989272c4c5 100644
--- a/openmp/runtime/CMakeLists.txt
+++ b/openmp/runtime/CMakeLists.txt
@@ -352,6 +352,10 @@ if(LIBOMP_OMPD_SUPPORT AND ((NOT LIBOMP_OMPT_SUPPORT) OR (NOT "${CMAKE_SYSTEM_NA
set(LIBOMP_OMPD_SUPPORT FALSE)
endif()
+# OMPX Taskgraph support
+# Whether to build with OMPX Taskgraph (e.g. task record & replay)
+set(LIBOMP_OMPX_TASKGRAPH FALSE CACHE BOOL "OMPX-taskgraph (task record & replay)?")
+
# Error check hwloc support after config-ix has run
if(LIBOMP_USE_HWLOC AND (NOT LIBOMP_HAVE_HWLOC))
libomp_error_say("Hwloc requested but not available")
@@ -421,6 +425,7 @@ if(${OPENMP_STANDALONE_BUILD})
libomp_say("Use Adaptive locks -- ${LIBOMP_USE_ADAPTIVE_LOCKS}")
libomp_say("Use quad precision -- ${LIBOMP_USE_QUAD_PRECISION}")
libomp_say("Use Hwloc library -- ${LIBOMP_USE_HWLOC}")
+ libomp_say("Use OMPX-taskgraph -- ${LIBOMP_OMPX_TASKGRAPH}")
endif()
add_subdirectory(src)
diff --git a/openmp/runtime/src/kmp.h b/openmp/runtime/src/kmp.h
index 8b98da6ae12f053..dc759ab1c527703 100644
--- a/openmp/runtime/src/kmp.h
+++ b/openmp/runtime/src/kmp.h
@@ -2550,6 +2550,7 @@ typedef struct {
} ed;
} kmp_event_t;
+#if OMPX_TASKGRAPH
// Initial number of allocated nodes while recording
#define INIT_MAPSIZE 50
@@ -2600,10 +2601,11 @@ typedef struct kmp_tdg_info {
extern int __kmp_tdg_dot;
extern kmp_int32 __kmp_max_tdgs;
extern kmp_tdg_info_t **__kmp_global_tdgs;
-extern kmp_int32 __kmp_curr_tdg_id;
+extern kmp_int32 __kmp_curr_tdg_idx;
extern kmp_int32 __kmp_successors_size;
extern std::atomic<kmp_int32> __kmp_tdg_task_id;
extern kmp_int32 __kmp_num_tdg;
+#endif
#ifdef BUILD_TIED_TASK_STACK
@@ -2625,8 +2627,12 @@ typedef struct kmp_task_stack {
typedef struct kmp_tasking_flags { /* Total struct must be exactly 32 bits */
#if __BYTE_ORDER__ == __ORDER_BIG_ENDIAN__
/* Same fields as in the #else branch, but in reverse order */
+#if OMPX_TASKGRAPH
unsigned reserved31 : 6;
unsigned onced : 1;
+#else
+ unsigned reserved31 : 7;
+#endif
unsigned native : 1;
unsigned freed : 1;
unsigned complete : 1;
@@ -2675,8 +2681,12 @@ typedef struct kmp_tasking_flags { /* Total struct must be exactly 32 bits */
unsigned complete : 1; /* 1==complete, 0==not complete */
unsigned freed : 1; /* 1==freed, 0==allocated */
unsigned native : 1; /* 1==gcc-compiled task, 0==intel */
+#if OMPX_TASKGRAPH
unsigned onced : 1; /* 1==ran once already, 0==never ran, record & replay purposes */
unsigned reserved31 : 6; /* reserved for library use */
+#else
+ unsigned reserved31 : 7; /* reserved for library use */
+#endif
#endif
} kmp_tasking_flags_t;
@@ -2726,8 +2736,10 @@ struct kmp_taskdata { /* aligned during dynamic allocation */
#if OMPT_SUPPORT
ompt_task_info_t ompt_task_info;
#endif
+#if OMPX_TASKGRAPH
bool is_taskgraph = 0; // whether the task is within a TDG
kmp_tdg_info_t *tdg; // used to associate task with a TDG
+#endif
kmp_target_data_t td_target_data;
}; // struct kmp_taskdata
@@ -4287,6 +4299,7 @@ KMP_EXPORT void __kmpc_init_nest_lock_with_hint(ident_t *loc, kmp_int32 gtid,
void **user_lock,
uintptr_t hint);
+#if OMPX_TASKGRAPH
// Taskgraph's Record & Replay mechanism
// __kmp_tdg_is_recording: check whether a given TDG is recording
// status: the tdg's current status
@@ -4299,9 +4312,7 @@ KMP_EXPORT kmp_int32 __kmpc_start_record_task(ident_t *loc, kmp_int32 gtid,
kmp_int32 tdg_id);
KMP_EXPORT void __kmpc_end_record_task(ident_t *loc, kmp_int32 gtid,
kmp_int32 input_flags, kmp_int32 tdg_id);
-KMP_EXPORT void __kmpc_taskgraph(ident_t *loc_ref, kmp_int32 gtid,
- kmp_int32 input_flags, kmp_uint32 tdg_id,
- void (*entry)(void *), void *args);
+#endif
/* Interface to fast scalable reduce methods routines */
KMP_EXPORT kmp_int32 __kmpc_reduce_nowait(
diff --git a/openmp/runtime/src/kmp_config.h.cmake b/openmp/runtime/src/kmp_config.h.cmake
index c1aaaaa122ae739..5f04301c91c60cd 100644
--- a/openmp/runtime/src/kmp_config.h.cmake
+++ b/openmp/runtime/src/kmp_config.h.cmake
@@ -46,6 +46,8 @@
#define OMPT_SUPPORT LIBOMP_OMPT_SUPPORT
#cmakedefine01 LIBOMP_OMPD_SUPPORT
#define OMPD_SUPPORT LIBOMP_OMPD_SUPPORT
+#cmakedefine01 LIBOMP_OMPX_TASKGRAPH
+#define OMPX_TASKGRAPH LIBOMP_OMPX_TASKGRAPH
#cmakedefine01 LIBOMP_PROFILING_SUPPORT
#define OMP_PROFILING_SUPPORT LIBOMP_PROFILING_SUPPORT
#cmakedefine01 LIBOMP_OMPT_OPTIONAL
diff --git a/openmp/runtime/src/kmp_global.cpp b/openmp/runtime/src/kmp_global.cpp
index 07e58850602a193..48097fb530d1c66 100644
--- a/openmp/runtime/src/kmp_global.cpp
+++ b/openmp/runtime/src/kmp_global.cpp
@@ -559,15 +559,17 @@ int __kmp_nesting_mode = 0;
int __kmp_nesting_mode_nlevels = 1;
int *__kmp_nesting_nth_level;
+#if OMPX_TASKGRAPH
// TDG record & replay
int __kmp_tdg_dot = 0;
kmp_int32 __kmp_max_tdgs = 100;
kmp_tdg_info_t **__kmp_global_tdgs = NULL;
-kmp_int32 __kmp_curr_tdg_id =
+kmp_int32 __kmp_curr_tdg_idx =
0; // Id of the current TDG being recorded or executed
kmp_int32 __kmp_num_tdg = 0;
kmp_int32 __kmp_successors_size = 10; // Initial succesor size list for
// recording
std::atomic<kmp_int32> __kmp_tdg_task_id = 0;
+#endif
// end of file //
diff --git a/openmp/runtime/src/kmp_settings.cpp b/openmp/runtime/src/kmp_settings.cpp
index 3d546c818fca9f9..e731bf45e8eee1f 100644
--- a/openmp/runtime/src/kmp_settings.cpp
+++ b/openmp/runtime/src/kmp_settings.cpp
@@ -1252,6 +1252,7 @@ static void __kmp_stg_parse_num_threads(char const *name, char const *value,
K_DIAG(1, ("__kmp_dflt_team_nth == %d\n", __kmp_dflt_team_nth));
} // __kmp_stg_parse_num_threads
+#if OMPX_TASKGRAPH
static void __kmp_stg_parse_max_tdgs(char const *name, char const *value,
void *data) {
__kmp_stg_parse_int(name, value, 0, INT_MAX, &__kmp_max_tdgs);
@@ -1271,6 +1272,7 @@ static void __kmp_stg_print_tdg_dot(kmp_str_buf_t *buffer, char const *name,
void *data) {
__kmp_stg_print_bool(buffer, name, __kmp_tdg_dot);
} // __kmp_stg_print_tdg_dot
+#endif
static void __kmp_stg_parse_num_hidden_helper_threads(char const *name,
char const *value,
@@ -5737,9 +5739,11 @@ static kmp_setting_t __kmp_stg_table[] = {
{"LIBOMP_NUM_HIDDEN_HELPER_THREADS",
__kmp_stg_parse_num_hidden_helper_threads,
__kmp_stg_print_num_hidden_helper_threads, NULL, 0, 0},
+#if OMPX_TASKGRAPH
{"KMP_MAX_TDGS", __kmp_stg_parse_max_tdgs, __kmp_std_print_max_tdgs, NULL,
0, 0},
{"KMP_TDG_DOT", __kmp_stg_parse_tdg_dot, __kmp_stg_print_tdg_dot, NULL, 0, 0},
+#endif
#if OMPT_SUPPORT
{"OMP_TOOL", __kmp_stg_parse_omp_tool, __kmp_stg_print_omp_tool, NULL, 0,
diff --git a/openmp/runtime/src/kmp_taskdeps.cpp b/openmp/runtime/src/kmp_taskdeps.cpp
index ce68dd03efe7508..3b39f503973635b 100644
--- a/openmp/runtime/src/kmp_taskdeps.cpp
+++ b/openmp/runtime/src/kmp_taskdeps.cpp
@@ -218,6 +218,7 @@ static kmp_depnode_list_t *__kmp_add_node(kmp_info_t *thread,
static inline void __kmp_track_dependence(kmp_int32 gtid, kmp_depnode_t *source,
kmp_depnode_t *sink,
kmp_task_t *sink_task) {
+#if OMPX_TASKGRAPH
kmp_taskdata_t *task_source = KMP_TASK_TO_TASKDATA(source->dn.task);
kmp_taskdata_t *task_sink = KMP_TASK_TO_TASKDATA(sink_task);
if (source->dn.task && sink_task) {
@@ -254,6 +255,7 @@ static inline void __kmp_track_dependence(kmp_int32 gtid, kmp_depnode_t *source,
sink_info->npredecessors++;
}
}
+#endif
#ifdef KMP_SUPPORT_GRAPH_OUTPUT
kmp_taskdata_t *task_source = KMP_TASK_TO_TASKDATA(source->dn.task);
// do not use sink->dn.task as that is only filled after the dependences
@@ -292,6 +294,7 @@ __kmp_depnode_link_successor(kmp_int32 gtid, kmp_info_t *thread,
// link node as successor of list elements
for (kmp_depnode_list_t *p = plist; p; p = p->next) {
kmp_depnode_t *dep = p->node;
+#if OMPX_TASKGRAPH
kmp_tdg_status tdg_status = KMP_TDG_NONE;
if (task) {
kmp_taskdata_t *td = KMP_TASK_TO_TASKDATA(task);
@@ -300,10 +303,13 @@ __kmp_depnode_link_successor(kmp_int32 gtid, kmp_info_t *thread,
if (__kmp_tdg_is_recording(tdg_status))
__kmp_track_dependence(gtid, dep, node, task);
}
+#endif
if (dep->dn.task) {
KMP_ACQUIRE_DEPNODE(gtid, dep);
if (dep->dn.task) {
+#if OMPX_TASKGRAPH
if (!(__kmp_tdg_is_recording(tdg_status)) && task)
+#endif
__kmp_track_dependence(gtid, dep, node, task);
dep->dn.successors = __kmp_add_node(thread, dep->dn.successors, node);
KA_TRACE(40, ("__kmp_process_deps: T#%d adding dependence from %p to "
@@ -326,6 +332,7 @@ static inline kmp_int32 __kmp_depnode_link_successor(kmp_int32 gtid,
if (!sink)
return 0;
kmp_int32 npredecessors = 0;
+#if OMPX_TASKGRAPH
kmp_tdg_status tdg_status = KMP_TDG_NONE;
kmp_taskdata_t *td = KMP_TASK_TO_TASKDATA(task);
if (task) {
@@ -334,17 +341,21 @@ static inline kmp_int32 __kmp_depnode_link_successor(kmp_int32 gtid,
if (__kmp_tdg_is_recording(tdg_status) && sink->dn.task)
__kmp_track_dependence(gtid, sink, source, task);
}
+#endif
if (sink->dn.task) {
// synchronously add source to sink' list of successors
KMP_ACQUIRE_DEPNODE(gtid, sink);
if (sink->dn.task) {
+#if OMPX_TASKGRAPH
if (!(__kmp_tdg_is_recording(tdg_status)) && task)
+#endif
__kmp_track_dependence(gtid, sink, source, task);
sink->dn.successors = __kmp_add_node(thread, sink->dn.successors, source);
KA_TRACE(40, ("__kmp_process_deps: T#%d adding dependence from %p to "
"%p\n",
gtid, KMP_TASK_TO_TASKDATA(sink->dn.task),
KMP_TASK_TO_TASKDATA(task)));
+#if OMPX_TASKGRAPH
if (__kmp_tdg_is_recording(tdg_status)) {
kmp_taskdata_t *tdd = KMP_TASK_TO_TASKDATA(sink->dn.task);
if (tdd->is_taskgraph) {
@@ -356,6 +367,7 @@ static inline kmp_int32 __kmp_depnode_link_successor(kmp_int32 gtid,
npredecessors--;
}
}
+#endif
npredecessors++;
}
KMP_RELEASE_DEPNODE(gtid, sink);
@@ -660,6 +672,7 @@ kmp_int32 __kmpc_omp_task_with_deps(ident_t *loc_ref, kmp_int32 gtid,
kmp_info_t *thread = __kmp_threads[gtid];
kmp_taskdata_t *current_task = thread->th.th_current_task;
+#if OMPX_TASKGRAPH
// record TDG with deps
if (new_taskdata->is_taskgraph &&
__kmp_tdg_is_recording(new_taskdata->tdg->tdg_status)) {
@@ -679,7 +692,7 @@ kmp_int32 __kmpc_omp_task_with_deps(ident_t *loc_ref, kmp_int32 gtid,
__kmp_free(old_record);
- for (kmp_uint i = old_size; i < new_size; i++) {
+ for (kmp_int i = old_size; i < new_size; i++) {
kmp_int32 *successorsList = (kmp_int32 *)__kmp_allocate(
__kmp_successors_size * sizeof(kmp_int32));
new_record[i].task = nullptr;
@@ -700,6 +713,7 @@ kmp_int32 __kmpc_omp_task_with_deps(ident_t *loc_ref, kmp_int32 gtid,
new_taskdata->td_parent;
KMP_ATOMIC_INC(&tdg->num_tasks);
}
+#endif
#if OMPT_SUPPORT
if (ompt_enabled.enabled) {
if (!current_task->ompt_task_info.frame.enter_frame.ptr)
diff --git a/openmp/runtime/src/kmp_taskdeps.h b/openmp/runtime/src/kmp_taskdeps.h
index a5069e1651b9c5c..d2ab515158011a1 100644
--- a/openmp/runtime/src/kmp_taskdeps.h
+++ b/openmp/runtime/src/kmp_taskdeps.h
@@ -93,6 +93,7 @@ extern void __kmpc_give_task(kmp_task_t *ptask, kmp_int32 start);
static inline void __kmp_release_deps(kmp_int32 gtid, kmp_taskdata_t *task) {
+#if OMPX_TASKGRAPH
if (task->is_taskgraph && !(__kmp_tdg_is_recording(task->tdg->tdg_status))) {
kmp_node_info_t *TaskInfo = &(task->tdg->record_map[task->td_task_id]);
@@ -106,6 +107,7 @@ static inline void __kmp_release_deps(kmp_int32 gtid, kmp_taskdata_t *task) {
}
return;
}
+#endif
kmp_info_t *thread = __kmp_threads[gtid];
kmp_depnode_t *node = task->td_depnode;
@@ -135,8 +137,10 @@ static inline void __kmp_release_deps(kmp_int32 gtid, kmp_taskdata_t *task) {
gtid, task));
KMP_ACQUIRE_DEPNODE(gtid, node);
+#if OMPX_TASKGRAPH
if (!task->is_taskgraph ||
(task->is_taskgraph && !__kmp_tdg_is_recording(task->tdg->tdg_status)))
+#endif
node->dn.task =
NULL; // mark this task as finished, so no new dependencies are generated
KMP_RELEASE_DEPNODE(gtid, node);
diff --git a/openmp/runtime/src/kmp_tasking.cpp b/openmp/runtime/src/kmp_tasking.cpp
index 364b26f6544e675..f90ae9cabab79fa 100644
--- a/openmp/runtime/src/kmp_tasking.cpp
+++ b/openmp/runtime/src/kmp_tasking.cpp
@@ -37,9 +37,10 @@ static void __kmp_alloc_task_deque(kmp_info_t *thread,
static int __kmp_realloc_task_threads_data(kmp_info_t *thread,
kmp_task_team_t *task_team);
static void __kmp_bottom_half_finish_proxy(kmp_int32 gtid, kmp_task_t *ptask);
-
+#if OMPX_TASKGRAPH
static kmp_tdg_info_t *__kmp_find_tdg(kmp_int32 tdg_id);
int __kmp_taskloop_task(int gtid, void *ptask);
+#endif
#ifdef BUILD_TIED_TASK_STACK
@@ -284,7 +285,11 @@ static bool __kmp_task_is_allowed(int gtid, const kmp_int32 is_constrained,
}
// Check mutexinoutset dependencies, acquire locks
kmp_depnode_t *node = tasknew->td_depnode;
+#if OMPX_TASKGRAPH
if (!tasknew->is_taskgraph && UNLIKELY(node && (node->dn.mtx_num_locks > 0))) {
+#else
+ if (UNLIKELY(node && (node->dn.mtx_num_locks > 0))) {
+#endif
for (int i = 0; i < node->dn.mtx_num_locks; ++i) {
KMP_DEBUG_ASSERT(node->dn.mtx_locks[i] != NULL);
if (__kmp_test_lock(node->dn.mtx_locks[i], gtid))
@@ -891,14 +896,17 @@ static void __kmp_free_task(kmp_int32 gtid, kmp_taskdata_t *taskdata,
task->data2.priority = 0;
taskdata->td_flags.freed = 1;
+#if OMPX_TASKGRAPH
// do not free tasks in taskgraph
if (!taskdata->is_taskgraph) {
+#endif
// deallocate the taskdata and shared variable blocks associated with this task
#if USE_FAST_MEMORY
__kmp_fast_free(thread, taskdata);
#else /* ! USE_FAST_MEMORY */
__kmp_thread_free(thread, taskdata);
#endif
+#if OMPX_TASKGRAPH
} else {
taskdata->td_flags.complete = 0;
taskdata->td_flags.started = 0;
@@ -914,6 +922,7 @@ static void __kmp_free_task(kmp_int32 gtid, kmp_taskdata_t *taskdata,
// start at one because counts current task and children
KMP_ATOMIC_ST_RLX(&taskdata->td_allocated_child_tasks, 1);
}
+#endif
KA_TRACE(20, ("__kmp_free_task: T#%d freed task %p\n", gtid, taskdata));
}
@@ -1001,8 +1010,10 @@ static bool __kmp_track_children_task(kmp_taskdata_t *taskdata) {
flags.detachable == TASK_DETACHABLE || flags.hidden_helper;
ret = ret ||
KMP_ATOMIC_LD_ACQ(&taskdata->td_parent->td_incomplete_child_tasks) > 0;
+#if OMPX_TASKGRAPH
if (taskdata->td_taskgroup && taskdata->is_taskgraph)
ret = ret || KMP_ATOMIC_LD_ACQ(&taskdata->td_taskgroup->count) > 0;
+#endif
return ret;
}
@@ -1022,8 +1033,10 @@ static void __kmp_task_finish(kmp_int32 gtid, kmp_task_t *task,
kmp_info_t *thread = __kmp_threads[gtid];
kmp_task_team_t *task_team =
thread->th.th_task_team; // might be NULL for serial teams...
+#if OMPX_TASKGRAPH
// to avoid seg fault when we need to access taskdata->td_flags after free when using vanilla taskloop
bool is_taskgraph;
+#endif
#if KMP_DEBUG
kmp_int32 children = 0;
#endif
@@ -1033,7 +1046,9 @@ static void __kmp_task_finish(kmp_int32 gtid, kmp_task_t *task,
KMP_DEBUG_ASSERT(taskdata->td_flags.tasktype == TASK_EXPLICIT);
+#if OMPX_TASKGRAPH
is_taskgraph = taskdata->is_taskgraph;
+#endif
// Pop task from stack if tied
#ifdef BUILD_TIED_TASK_STACK
@@ -1141,7 +1156,9 @@ static void __kmp_task_finish(kmp_int32 gtid, kmp_task_t *task,
if (completed) {
taskdata->td_flags.complete = 1; // mark the task as completed
+#if OMPX_TASKGRAPH
taskdata->td_flags.onced = 1; // mark the task as ran once already
+#endif
#if OMPT_SUPPORT
// This is not a detached task, we are done here
@@ -1158,7 +1175,11 @@ static void __kmp_task_finish(kmp_int32 gtid, kmp_task_t *task,
#endif
KMP_ATOMIC_DEC(&taskdata->td_parent->td_incomplete_child_tasks);
KMP_DEBUG_ASSERT(children >= 0);
+#if OMPX_TASKGRAPH
if (taskdata->td_taskgroup && !taskdata->is_taskgraph)
+#else
+ if (taskdata->td_taskgroup)
+#endif
KMP_ATOMIC_DEC(&taskdata->td_taskgroup->count);
} else if (task_team && (task_team->tt.tt_found_proxy_tasks ||
task_team->tt.tt_hidden_helper_task_encountered)) {
@@ -1197,6 +1218,7 @@ static void __kmp_task_finish(kmp_int32 gtid, kmp_task_t *task,
// KMP_DEBUG_ASSERT( resumed_task->td_flags.executing == 0 );
resumed_task->td_flags.executing = 1; // resume previous task
+#if OMPX_TASKGRAPH
if (is_taskgraph && __kmp_track_children_task(taskdata) &&
taskdata->td_taskgroup) {
// TDG: we only release taskgroup barrier here because
@@ -1207,6 +1229,7 @@ static void __kmp_task_finish(kmp_int32 gtid, kmp_task_t *task,
// non-TDG implementation because we never reuse a task(data) structure
KMP_ATOMIC_DEC(&taskdata->td_taskgroup->count);
}
+#endif
KA_TRACE(
10, ("__kmp_task_finish(exit): T#%d finished task %p, resuming task %p\n",
@@ -1324,7 +1347,9 @@ void __kmp_init_implicit_task(ident_t *loc_ref, kmp_info_t *this_thr,
task->td_flags.executing = 1;
task->td_flags.complete = 0;
task->td_flags.freed = 0;
+#if OMPX_TASKGRAPH
task->td_flags.onced = 0;
+#endif
task->td_depnode = NULL;
task->td_last_tied = task;
@@ -1361,7 +1386,9 @@ void __kmp_finish_implicit_task(kmp_info_t *thread) {
if (task->td_dephash) {
int children;
task->td_flags.complete = 1;
+#if OMPX_TASKGRAPH
task->td_flags.onced = 1;
+#endif
children = KMP_ATOMIC_LD_ACQ(&task->td_incomplete_child_tasks);
kmp_tasking_flags_t flags_old = task->td_flags;
if (children == 0 && flags_old.complete == 1) {
@@ -1591,7 +1618,9 @@ kmp_task_t *__kmp_task_alloc(ident_t *loc_ref, kmp_int32 gtid,
taskdata->td_flags.executing = 0;
taskdata->td_flags.complete = 0;
taskdata->td_flags.freed = 0;
+#if OMPX_TASKGRAPH
taskdata->td_flags.onced = 0;
+#endif
KMP_ATOMIC_ST_RLX(&taskdata->td_incomplete_child_tasks, 0);
// start at one because counts current task and children
KMP_ATOMIC_ST_RLX(&taskdata->td_allocated_child_tasks, 1);
@@ -1627,13 +1656,15 @@ kmp_task_t *__kmp_task_alloc(ident_t *loc_ref, kmp_int32 gtid,
}
}
- kmp_tdg_info_t *tdg = __kmp_find_tdg(__kmp_curr_tdg_id);
+#if OMPX_TASKGRAPH
+ kmp_tdg_info_t *tdg = __kmp_find_tdg(__kmp_curr_tdg_idx);
if (tdg && __kmp_tdg_is_recording(tdg->tdg_status) &&
(task_entry != (kmp_routine_entry_t)__kmp_taskloop_task)) {
taskdata->is_taskgraph = 1;
- taskdata->tdg = tdg;
+ taskdata->tdg = __kmp_global_tdgs[__kmp_curr_tdg_idx];
taskdata->td_task_id = KMP_ATOMIC_INC(&__kmp_tdg_task_id);
}
+#endif
KA_TRACE(20, ("__kmp_task_alloc(exit): T#%d created task %p parent=%p\n",
gtid, taskdata, taskdata->td_parent));
@@ -1981,6 +2012,7 @@ kmp_int32 __kmp_omp_task(kmp_int32 gtid, kmp_task_t *new_task,
bool serialize_immediate) {
kmp_taskdata_t *new_taskdata = KMP_TASK_TO_TASKDATA(new_task);
+#if OMPX_TASKGRAPH
if (new_taskdata->is_taskgraph &&
__kmp_tdg_is_recording(new_taskdata->tdg->tdg_status)) {
kmp_tdg_info_t *tdg = new_taskdata->tdg;
@@ -2001,7 +2033,7 @@ kmp_int32 __kmp_omp_task(kmp_int32 gtid, kmp_task_t *new_task,
__kmp_free(old_record);
- for (kmp_uint i = old_size; i < new_size; i++) {
+ for (kmp_int i = old_size; i < new_size; i++) {
kmp_int32 *successorsList = (kmp_int32 *)__kmp_allocate(
__kmp_successors_size * sizeof(kmp_int32));
new_record[i].task = nullptr;
@@ -2025,6 +2057,7 @@ kmp_int32 __kmp_omp_task(kmp_int32 gtid, kmp_task_t *new_task,
KMP_ATOMIC_INC(&tdg->num_tasks);
}
}
+#endif
/* Should we execute the new task or queue it? For now, let's just always try
to queue it. If the queue fills up, then we'll execute it. */
@@ -2541,15 +2574,17 @@ the reduction either does not use omp_orig object, or the omp_orig is accessible
without help of the runtime library.
*/
void *__kmpc_task_reduction_init(int gtid, int num, void *data) {
- kmp_tdg_info_t *tdg = __kmp_find_tdg(__kmp_curr_tdg_id);
+#if OMPX_TASKGRAPH
+ kmp_tdg_info_t *tdg = __kmp_find_tdg(__kmp_curr_tdg_idx);
if (tdg && __kmp_tdg_is_recording(tdg->tdg_status)) {
- kmp_tdg_info_t *this_tdg = __kmp_find_tdg(__kmp_curr_tdg_id);
+ kmp_tdg_info_t *this_tdg = __kmp_global_tdgs[__kmp_curr_tdg_idx];
this_tdg->rec_taskred_data =
__kmp_allocate(sizeof(kmp_task_red_input_t) * num);
this_tdg->rec_num_taskred = num;
KMP_MEMCPY(this_tdg->rec_taskred_data, data,
sizeof(kmp_task_red_input_t) * num);
}
+#endif
return __kmp_task_reduction_init(gtid, num, (kmp_task_red_input_t *)data);
}
@@ -2566,14 +2601,17 @@ Note: this entry supposes the optional compiler-generated initializer routine
has two parameters, pointer to object to be initialized and pointer to omp_orig
*/
void *__kmpc_taskred_init(int gtid, int num, void *data) {
- kmp_tdg_info_t *tdg = __kmp_find_tdg(__kmp_curr_tdg_id);
+#if OMPX_TASKGRAPH
+ kmp_tdg_info_t *tdg = __kmp_find_tdg(__kmp_curr_tdg_idx);
if (tdg && __kmp_tdg_is_recording(tdg->tdg_status)) {
- tdg->rec_taskred_data =
+ kmp_tdg_info_t *this_tdg = __kmp_global_tdgs[__kmp_curr_tdg_idx];
+ this_tdg->rec_taskred_data =
__kmp_allocate(sizeof(kmp_task_red_input_t) * num);
- tdg->rec_num_taskred = num;
- KMP_MEMCPY(tdg->rec_taskred_data, data,
+ this_tdg->rec_num_taskred = num;
+ KMP_MEMCPY(this_tdg->rec_taskred_data, data,
sizeof(kmp_task_red_input_t) * num);
}
+#endif
return __kmp_task_reduction_init(gtid, num, (kmp_taskred_input_t *)data);
}
@@ -2620,15 +2658,17 @@ void *__kmpc_task_reduction_get_th_data(int gtid, void *tskgrp, void *data) {
kmp_int32 num = tg->reduce_num_data;
kmp_int32 tid = thread->th.th_info.ds.ds_tid;
+#if OMPX_TASKGRAPH
if ((thread->th.th_current_task->is_taskgraph) &&
(!__kmp_tdg_is_recording(
- __kmp_find_tdg(__kmp_curr_tdg_id)->tdg_status))) {
+ __kmp_global_tdgs[__kmp_curr_tdg_idx]->tdg_status))) {
tg = thread->th.th_current_task->td_taskgroup;
KMP_ASSERT(tg != NULL);
KMP_ASSERT(tg->reduce_data != NULL);
arr = (kmp_taskred_data_t *)(tg->reduce_data);
num = tg->reduce_num_data;
}
+#endif
KMP_ASSERT(data != NULL);
while (tg != NULL) {
@@ -4406,7 +4446,9 @@ static void __kmp_first_top_half_finish_proxy(kmp_taskdata_t *taskdata) {
KMP_DEBUG_ASSERT(taskdata->td_flags.freed == 0);
taskdata->td_flags.complete = 1; // mark the task as completed
+#if OMPX_TASKGRAPH
taskdata->td_flags.onced = 1;
+#endif
if (taskdata->td_taskgroup)
KMP_ATOMIC_DEC(&taskdata->td_taskgroup->count);
@@ -4608,8 +4650,11 @@ void __kmp_fulfill_event(kmp_event_t *event) {
// taskloop_recur: used only when dealing with taskgraph,
// indicating whether we need to update task->td_task_id
// returns: a pointer to the allocated kmp_task_t structure (task).
-kmp_task_t *__kmp_task_dup_alloc(kmp_info_t *thread, kmp_task_t *task_src,
- int taskloop_recur) {
+kmp_task_t *__kmp_task_dup_alloc(kmp_info_t *thread, kmp_task_t *task_src
+#if OMPX_TASKGRAPH
+ , int taskloop_recur
+#endif
+) {
kmp_task_t *task;
kmp_taskdata_t *taskdata;
kmp_taskdata_t *taskdata_src = KMP_TASK_TO_TASKDATA(task_src);
@@ -4637,11 +4682,15 @@ kmp_task_t *__kmp_task_dup_alloc(kmp_info_t *thread, kmp_task_t *task_src,
task = KMP_TASKDATA_TO_TASK(taskdata);
// Initialize new task (only specific fields not affected by memcpy)
+#if OMPX_TASKGRAPH
if (!taskdata->is_taskgraph || taskloop_recur)
taskdata->td_task_id = KMP_GEN_TASK_ID();
else if (taskdata->is_taskgraph &&
__kmp_tdg_is_recording(taskdata_src->tdg->tdg_status))
taskdata->td_task_id = KMP_ATOMIC_INC(&__kmp_tdg_task_id);
+#else
+ taskdata->td_task_id = KMP_GEN_TASK_ID();
+#endif
if (task->shareds != NULL) { // need setup shareds pointer
shareds_offset = (char *)task_src->shareds - (char *)taskdata_src;
task->shareds = &((char *)taskdata)[shareds_offset];
@@ -4869,7 +4918,11 @@ void __kmp_taskloop_linear(ident_t *loc, int gtid, kmp_task_t *task,
}
}
+#if OMPX_TASKGRAPH
next_task = __kmp_task_dup_alloc(thread, task, /* taskloop_recur */ 0);
+#else
+ next_task = __kmp_task_dup_alloc(thread, task); // allocate new task
+#endif
kmp_taskdata_t *next_taskdata = KMP_TASK_TO_TASKDATA(next_task);
kmp_taskloop_bounds_t next_task_bounds =
@@ -5067,8 +5120,12 @@ void __kmp_taskloop_recur(ident_t *loc, int gtid, kmp_task_t *task,
lb1 = ub0 + st;
// create pattern task for 2nd half of the loop
+#if OMPX_TASKGRAPH
next_task = __kmp_task_dup_alloc(thread, task,
/* taskloop_recur */ 1);
+#else
+ next_task = __kmp_task_dup_alloc(thread, task); // duplicate the task
+#endif
// adjust lower bound (upper bound is not changed) for the 2nd half
*(kmp_uint64 *)((char *)next_task + lower_offset) = lb1;
if (ptask_dup != NULL) // construct firstprivates, etc.
@@ -5101,9 +5158,11 @@ void __kmp_taskloop_recur(ident_t *loc, int gtid, kmp_task_t *task,
p->codeptr_ra = codeptr_ra;
#endif
+#if OMPX_TASKGRAPH
kmp_taskdata_t *new_task_data = KMP_TASK_TO_TASKDATA(new_task);
new_task_data->tdg = taskdata->tdg;
new_task_data->is_taskgraph = 0;
+#endif
#if OMPT_SUPPORT
// schedule new task with correct return address for OMPT events
@@ -5144,7 +5203,9 @@ static void __kmp_taskloop(ident_t *loc, int gtid, kmp_task_t *task, int if_val,
__kmpc_taskgroup(loc, gtid);
}
+#if OMPX_TASKGRAPH
KMP_ATOMIC_DEC(&__kmp_tdg_task_id);
+#endif
// =========================================================================
// calculate loop parameters
kmp_taskloop_bounds_t task_bounds(task, lb, ub);
@@ -5393,24 +5454,7 @@ bool __kmpc_omp_has_task_team(kmp_int32 gtid) {
return taskdata->td_task_team != NULL;
}
-// __kmpc_taskgraph: record or replay taskgraph
-// loc_ref: Location of TDG, not used yet
-// gtid: Global Thread ID of the encountering thread
-// input_flags: Flags associated with the TDG
-// tdg_id: ID of the TDG to record, for now, incremental integer
-// entry: Pointer to the entry function
-// args: Pointer to the function arguments
-void __kmpc_taskgraph(ident_t *loc_ref, kmp_int32 gtid, kmp_int32 input_flags,
- kmp_uint32 tdg_id, void (*entry)(void *), void *args) {
- kmp_int32 res = __kmpc_start_record_task(loc_ref, gtid, input_flags, tdg_id);
- // When res = 1, we either start recording or only execute tasks
- // without recording. Need to execute entry function in both cases.
- if (res)
- entry(args);
-
- __kmpc_end_record_task(loc_ref, gtid, input_flags, tdg_id);
-}
-
+#if OMPX_TASKGRAPH
// __kmp_find_tdg: identify a TDG through its ID
// gtid: Global Thread ID
// tdg_id: ID of the TDG
@@ -5425,15 +5469,9 @@ static kmp_tdg_info_t *__kmp_find_tdg(kmp_int32 tdg_id) {
__kmp_global_tdgs = (kmp_tdg_info_t **)__kmp_allocate(
sizeof(kmp_tdg_info_t *) * __kmp_max_tdgs);
- for (kmp_int32 i = 0; i < __kmp_num_tdg; ++i) {
- if ((__kmp_global_tdgs[i]) &&
- (__kmp_global_tdgs[i]->tdg_id == tdg_id) &&
- (__kmp_global_tdgs[i]->tdg_status != KMP_TDG_NONE)) {
- res = __kmp_global_tdgs[i];
- __kmp_curr_tdg_id = tdg_id;
- break;
- }
- }
+ if ((__kmp_global_tdgs[tdg_id]) &&
+ (__kmp_global_tdgs[tdg_id]->tdg_status != KMP_TDG_NONE))
+ res = __kmp_global_tdgs[tdg_id];
return res;
}
@@ -5441,7 +5479,7 @@ static kmp_tdg_info_t *__kmp_find_tdg(kmp_int32 tdg_id) {
// tdg: ID of the TDG
void __kmp_print_tdg_dot(kmp_tdg_info_t *tdg) {
kmp_int32 tdg_id = tdg->tdg_id;
- KA_TRACE(10, ("__kmp_print_tdg_dot(enter): T#%d tdg_id=%d \n", __kmp_get_gtid(), tdg_id));
+ KA_TRACE(10, ("__kmp_print_tdg_dot(enter): T#%d tdg_id=%d \n", gtid, tdg_id));
char file_name[20];
sprintf(file_name, "tdg_%d.dot", tdg_id);
@@ -5467,10 +5505,10 @@ void __kmp_print_tdg_dot(kmp_tdg_info_t *tdg) {
}
}
fprintf(tdg_file, "}");
- KA_TRACE(10, ("__kmp_print_tdg_dot(exit): T#%d tdg_id=%d \n", __kmp_get_gtid(), tdg_id));
+ KA_TRACE(10, ("__kmp_print_tdg_dot(exit): T#%d tdg_id=%d \n", gtid, tdg_id));
}
-// __kmp_exec_tdg: launch the execution of a previous
+// __kmp_start_record: launch the execution of a previous
// recorded TDG
// gtid: Global Thread ID
// tdg: ID of the TDG
@@ -5532,7 +5570,7 @@ static inline void __kmp_start_record(kmp_int32 gtid,
kmp_int32 tdg_id) {
kmp_tdg_info_t *tdg =
(kmp_tdg_info_t *)__kmp_allocate(sizeof(kmp_tdg_info_t));
- __kmp_global_tdgs[__kmp_num_tdg-1] = tdg;
+ __kmp_global_tdgs[__kmp_curr_tdg_idx] = tdg;
// Initializing the TDG structure
tdg->tdg_id = tdg_id;
tdg->map_size = INIT_MAPSIZE;
@@ -5557,7 +5595,7 @@ static inline void __kmp_start_record(kmp_int32 gtid,
KMP_ATOMIC_ST_RLX(&this_record_map[i].npredecessors_counter, 0);
}
- tdg->record_map = this_record_map;
+ __kmp_global_tdgs[__kmp_curr_tdg_idx]->record_map = this_record_map;
}
// __kmpc_start_record_task: Wrapper around __kmp_start_record to mark
@@ -5591,14 +5629,10 @@ kmp_int32 __kmpc_start_record_task(ident_t *loc_ref, kmp_int32 gtid,
__kmp_exec_tdg(gtid, tdg);
res = 0;
} else {
- if (__kmp_num_tdg < __kmp_max_tdgs) {
- __kmp_curr_tdg_id = tdg_id;
- __kmp_num_tdg++;
- KMP_DEBUG_ASSERT(__kmp_num_tdg <= __kmp_max_tdgs);
- __kmp_start_record(gtid, flags, tdg_id);
- }
- // if no TDG found, need to execute the task
- // even not recording
+ __kmp_curr_tdg_idx = tdg_id;
+ KMP_DEBUG_ASSERT(__kmp_curr_tdg_idx < __kmp_max_tdgs);
+ __kmp_start_record(gtid, flags, tdg_id);
+ __kmp_num_tdg++;
res = 1;
}
KA_TRACE(10, ("__kmpc_start_record_task(exit): T#%d TDG %d starts to %s\n",
@@ -5671,4 +5705,5 @@ void __kmpc_end_record_task(ident_t *loc_ref, kmp_int32 gtid,
KA_TRACE(10, ("__kmpc_end_record_task(exit): T#%d loc=%p finished recording"
" tdg=%d, its status is now READY\n",
gtid, loc_ref, tdg_id));
-}
\ No newline at end of file
+}
+#endif
diff --git a/openmp/runtime/test/CMakeLists.txt b/openmp/runtime/test/CMakeLists.txt
index 05b517fb920fdc7..a7790804542b7ee 100644
--- a/openmp/runtime/test/CMakeLists.txt
+++ b/openmp/runtime/test/CMakeLists.txt
@@ -30,6 +30,7 @@ update_test_compiler_features()
pythonize_bool(LIBOMP_USE_HWLOC)
pythonize_bool(LIBOMP_OMPT_SUPPORT)
pythonize_bool(LIBOMP_OMPT_OPTIONAL)
+pythonize_bool(LIBOMP_OMPX_TASKGRAPH)
pythonize_bool(LIBOMP_HAVE_LIBM)
pythonize_bool(LIBOMP_HAVE_LIBATOMIC)
pythonize_bool(OPENMP_STANDALONE_BUILD)
diff --git a/openmp/runtime/test/lit.cfg b/openmp/runtime/test/lit.cfg
index 7f7003a24048037..27ff057c85f60f2 100644
--- a/openmp/runtime/test/lit.cfg
+++ b/openmp/runtime/test/lit.cfg
@@ -105,6 +105,9 @@ if config.has_ompt:
# for callback.h
config.test_flags += " -I " + config.test_source_root + "/ompt"
+if config.has_ompx_taskgraph:
+ config.available_features.add("ompx_taskgraph")
+
if 'Linux' in config.operating_system:
config.available_features.add("linux")
diff --git a/openmp/runtime/test/lit.site.cfg.in b/openmp/runtime/test/lit.site.cfg.in
index 45a18b480130f6a..d6c259280619be9 100644
--- a/openmp/runtime/test/lit.site.cfg.in
+++ b/openmp/runtime/test/lit.site.cfg.in
@@ -15,6 +15,7 @@ config.operating_system = "@CMAKE_SYSTEM_NAME@"
config.hwloc_library_dir = "@LIBOMP_HWLOC_LIBRARY_DIR@"
config.using_hwloc = @LIBOMP_USE_HWLOC@
config.has_ompt = @LIBOMP_OMPT_SUPPORT@ and @LIBOMP_OMPT_OPTIONAL@
+config.has_ompx_taskgraph = @LIBOMP_OMPX_TASKGRAPH@
config.has_libm = @LIBOMP_HAVE_LIBM@
config.has_libatomic = @LIBOMP_HAVE_LIBATOMIC@
config.is_standalone_build = @OPENMP_STANDALONE_BUILD@
diff --git a/openmp/runtime/test/tasking/omp_record_replay.cpp b/openmp/runtime/test/tasking/omp_record_replay.cpp
index 54e8090c486ad54..69ad98003a0d699 100644
--- a/openmp/runtime/test/tasking/omp_record_replay.cpp
+++ b/openmp/runtime/test/tasking/omp_record_replay.cpp
@@ -1,3 +1,4 @@
+// REQUIRES: ompx_taskgraph
// RUN: %libomp-cxx-compile-and-run
#include <iostream>
#include <cassert>
@@ -28,12 +29,14 @@ int main() {
#pragma omp parallel
#pragma omp single
for (int iter = 0; iter < NT; ++iter) {
- #pragma ompx taskgraph
- {
+ int gtid = __kmpc_global_thread_num(nullptr);
+ int res = __kmpc_start_record_task(nullptr, gtid, /* kmp_tdg_flags */ 0, /* tdg_id */0);
+ if (res) {
num_tasks++;
#pragma omp task
func(&num_exec);
}
+ __kmpc_end_record_task(nullptr, gtid, /* kmp_tdg_flags */0, /* tdg_id */0);
}
assert(num_tasks==1);
diff --git a/openmp/runtime/test/tasking/omp_record_replay_deps.cpp b/openmp/runtime/test/tasking/omp_record_replay_deps.cpp
index c370ad34b5528bf..9b6b370b30efc15 100644
--- a/openmp/runtime/test/tasking/omp_record_replay_deps.cpp
+++ b/openmp/runtime/test/tasking/omp_record_replay_deps.cpp
@@ -1,3 +1,4 @@
+// REQUIRES: ompx_taskgraph
// RUN: %libomp-cxx-compile-and-run
#include <iostream>
#include <cassert>
@@ -42,8 +43,9 @@ int main() {
#pragma omp parallel
#pragma omp single
for (int iter = 0; iter < NT; ++iter) {
- #pragma ompx taskgraph
- {
+ int gtid = __kmpc_global_thread_num(nullptr);
+ int res = __kmpc_start_record_task(nullptr, gtid, /* kmp_tdg_flags */0, /* tdg_id */0);
+ if (res) {
#pragma omp task depend(out:y)
add();
#pragma omp task depend(out:x)
@@ -51,6 +53,7 @@ int main() {
#pragma omp task depend(in:x,y)
mult();
}
+ __kmpc_end_record_task(nullptr, gtid, /* kmp_tdg_flags */0, /* tdg_id */0);
}
assert(val==0);
diff --git a/openmp/runtime/test/tasking/omp_record_replay_multiTDGs.cpp b/openmp/runtime/test/tasking/omp_record_replay_multiTDGs.cpp
index 282625ddb47826c..03252843689c401 100644
--- a/openmp/runtime/test/tasking/omp_record_replay_multiTDGs.cpp
+++ b/openmp/runtime/test/tasking/omp_record_replay_multiTDGs.cpp
@@ -1,3 +1,4 @@
+// REQUIRES: ompx_taskgraph
// RUN: %libomp-cxx-compile-and-run
#include <iostream>
#include <cassert>
@@ -41,8 +42,9 @@ int main() {
#pragma omp parallel
#pragma omp single
for (int iter = 0; iter < NT; ++iter) {
- #pragma ompx taskgraph
- {
+ int gtid = __kmpc_global_thread_num(nullptr);
+ int res = __kmpc_start_record_task(nullptr, gtid, /* kmp_tdg_flags */ 0, /* tdg_id */0);
+ if (res) {
num_tasks++;
#pragma omp task depend(out:y)
add();
@@ -51,8 +53,9 @@ int main() {
#pragma omp task depend(in:x,y)
mult();
}
- #pragma ompx taskgraph
- {
+ __kmpc_end_record_task(nullptr, gtid, /* kmp_tdg_flags */0, /* tdg_id */0);
+ res = __kmpc_start_record_task(nullptr, gtid, /* kmp_tdg_flags */ 0, /* tdg_id */1);
+ if (res) {
num_tasks++;
#pragma omp task depend(out:y)
add();
@@ -61,6 +64,7 @@ int main() {
#pragma omp task depend(in:x,y)
mult();
}
+ __kmpc_end_record_task(nullptr, gtid, /* kmp_tdg_flags */0, /* tdg_id */1);
}
assert(num_tasks==2);
diff --git a/openmp/runtime/test/tasking/omp_record_replay_print_dot.cpp b/openmp/runtime/test/tasking/omp_record_replay_print_dot.cpp
index 522068c359e6a59..2fe55f081542903 100644
--- a/openmp/runtime/test/tasking/omp_record_replay_print_dot.cpp
+++ b/openmp/runtime/test/tasking/omp_record_replay_print_dot.cpp
@@ -1,3 +1,4 @@
+// REQUIRES: ompx_taskgraph
// RUN: %libomp-cxx-compile-and-run
#include <iostream>
#include <fstream>
@@ -25,7 +26,7 @@ void func(int *num_exec) {
std::string tdg_string= "digraph TDG {\n"
" compound=true\n"
" subgraph cluster {\n"
-" label=TDG_33263\n"
+" label=TDG_0\n"
" 0[style=bold]\n"
" 1[style=bold]\n"
" 2[style=bold]\n"
@@ -46,8 +47,9 @@ int main() {
#pragma omp parallel
#pragma omp single
{
- #pragma ompx taskgraph
- {
+ int gtid = __kmpc_global_thread_num(nullptr);
+ int res = __kmpc_start_record_task(nullptr, gtid, /* kmp_tdg_flags */ 0, /* tdg_id */ 0);
+ if (res) {
#pragma omp task depend(out : x)
func(&num_exec);
#pragma omp task depend(in : x) depend(out : y)
@@ -57,11 +59,13 @@ int main() {
#pragma omp task depend(in : y)
func(&num_exec);
}
+
+ __kmpc_end_record_task(nullptr, gtid, /* kmp_tdg_flags */ 0, /* tdg_id */ 0);
}
assert(num_exec == 4);
- std::ifstream tdg_file("tdg_33263.dot");
+ std::ifstream tdg_file("tdg_0.dot");
assert(tdg_file.is_open());
std::stringstream tdg_file_stream;
diff --git a/openmp/runtime/test/tasking/omp_record_replay_taskloop.cpp b/openmp/runtime/test/tasking/omp_record_replay_taskloop.cpp
index dd814ff36e9e7a1..3d88faeeb28eea1 100644
--- a/openmp/runtime/test/tasking/omp_record_replay_taskloop.cpp
+++ b/openmp/runtime/test/tasking/omp_record_replay_taskloop.cpp
@@ -1,3 +1,4 @@
+// REQUIRES: ompx_taskgraph
// RUN: %libomp-cxx-compile-and-run
#include <iostream>
#include <cassert>
@@ -29,14 +30,16 @@ int main() {
#pragma omp parallel
#pragma omp single
for (int iter = 0; iter < NT; ++iter) {
- #pragma ompx taskgraph
- {
+ int gtid = __kmpc_global_thread_num(nullptr);
+ int res = __kmpc_start_record_task(nullptr, gtid, /* kmp_tdg_flags */0, /* tdg_id */0);
+ if (res) {
num_tasks++;
#pragma omp taskloop reduction(+:sum) num_tasks(4096)
for (int i = 0; i < N; ++i) {
sum += array[i];
}
}
+ __kmpc_end_record_task(nullptr, gtid, /* kmp_tdg_flags */0, /* tdg_id */0);
}
assert(sum==N*NT);
assert(num_tasks==1);
More information about the llvm-commits
mailing list