Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

[OpenMP] Introduce support for OMPX extensions and taskgraph frontend #66919

Open
wants to merge 3 commits into
base: main
Choose a base branch
from

Conversation

Munesanz
Copy link
Contributor

@Munesanz Munesanz commented Sep 20, 2023

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.

@llvmbot llvmbot added clang Clang issues not falling into any other category clang:frontend Language frontend issues, e.g. anything involving "Sema" clang:modules C++20 modules and Clang Header Modules clang:codegen clang:static analyzer flang:openmp labels Sep 20, 2023
@llvmbot
Copy link
Collaborator

llvmbot commented Sep 20, 2023

@llvm/pr-subscribers-openmp
@llvm/pr-subscribers-flang-openmp
@llvm/pr-subscribers-clang
@llvm/pr-subscribers-clang-modules
@llvm/pr-subscribers-clang-static-analyzer-1

@llvm/pr-subscribers-clang-codegen

Changes

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.


Patch is 100.08 KiB, truncated to 20.00 KiB below, full version: https://github.com/llvm/llvm-project/pull/66919.diff

62 Files Affected:

  • (modified) clang/include/clang-c/Index.h (+5-1)
  • (modified) clang/include/clang/AST/RecursiveASTVisitor.h (+3)
  • (modified) clang/include/clang/AST/StmtOpenMP.h (+49)
  • (modified) clang/include/clang/Basic/DiagnosticParseKinds.td (+8)
  • (modified) clang/include/clang/Basic/StmtNodes.td (+1)
  • (modified) clang/include/clang/Basic/TokenKinds.def (+3)
  • (modified) clang/include/clang/Parse/Parser.h (+11-1)
  • (modified) clang/include/clang/Sema/Sema.h (+4)
  • (modified) clang/include/clang/Serialization/ASTBitCodes.h (+1)
  • (modified) clang/lib/AST/StmtOpenMP.cpp (+15)
  • (modified) clang/lib/AST/StmtPrinter.cpp (+5)
  • (modified) clang/lib/AST/StmtProfile.cpp (+4)
  • (modified) clang/lib/Basic/OpenMPKinds.cpp (+3)
  • (modified) clang/lib/CodeGen/CGOpenMPRuntime.cpp (+74)
  • (modified) clang/lib/CodeGen/CGOpenMPRuntime.h (+8)
  • (modified) clang/lib/CodeGen/CGOpenMPRuntimeGPU.cpp (+2)
  • (modified) clang/lib/CodeGen/CGStmt.cpp (+3)
  • (modified) clang/lib/CodeGen/CGStmtOpenMP.cpp (+6)
  • (modified) clang/lib/CodeGen/CodeGenFunction.h (+1)
  • (modified) clang/lib/Frontend/PrintPreprocessedOutput.cpp (+7)
  • (modified) clang/lib/Parse/ParseCXXInlineMethods.cpp (+7)
  • (modified) clang/lib/Parse/ParseDecl.cpp (+9)
  • (modified) clang/lib/Parse/ParseDeclCXX.cpp (+17-7)
  • (modified) clang/lib/Parse/ParseOpenMP.cpp (+71-5)
  • (modified) clang/lib/Parse/ParsePragma.cpp (+73-2)
  • (modified) clang/lib/Parse/ParseStmt.cpp (+1)
  • (modified) clang/lib/Parse/Parser.cpp (+6)
  • (modified) clang/lib/Sema/SemaExceptionSpec.cpp (+1)
  • (modified) clang/lib/Sema/SemaOpenMP.cpp (+26)
  • (modified) clang/lib/Sema/TreeTransform.h (+11)
  • (modified) clang/lib/Serialization/ASTReaderStmt.cpp (+10)
  • (modified) clang/lib/Serialization/ASTWriter.cpp (+1)
  • (modified) clang/lib/Serialization/ASTWriterStmt.cpp (+6)
  • (modified) clang/lib/StaticAnalyzer/Core/ExprEngine.cpp (+1)
  • (added) clang/test/OpenMP/ompx_extensions_messages.cpp (+12)
  • (added) clang/test/OpenMP/ompx_taskgraph_ast_print.cpp (+34)
  • (added) clang/test/OpenMP/ompx_taskgraph_codegen.cpp (+29)
  • (modified) clang/tools/libclang/CIndex.cpp (+2)
  • (modified) clang/tools/libclang/CXCursor.cpp (+3)
  • (modified) llvm/include/llvm/Frontend/Directive/DirectiveBase.td (+6)
  • (modified) llvm/include/llvm/Frontend/OpenMP/OMP.td (+5)
  • (modified) llvm/include/llvm/Frontend/OpenMP/OMPKinds.def (+1)
  • (modified) llvm/include/llvm/TableGen/DirectiveEmitter.h (+2)
  • (modified) llvm/test/TableGen/directive1.td (+22)
  • (modified) llvm/test/TableGen/directive2.td (+22)
  • (modified) llvm/utils/TableGen/DirectiveEmitter.cpp (+72)
  • (modified) openmp/runtime/CMakeLists.txt (-5)
  • (modified) openmp/runtime/src/kmp.h (+4-11)
  • (modified) openmp/runtime/src/kmp_config.h.cmake (-2)
  • (modified) openmp/runtime/src/kmp_global.cpp (+1-3)
  • (modified) openmp/runtime/src/kmp_settings.cpp (-4)
  • (modified) openmp/runtime/src/kmp_taskdeps.cpp (+1-15)
  • (modified) openmp/runtime/src/kmp_taskdeps.h (-4)
  • (modified) openmp/runtime/src/kmp_tasking.cpp (+54-89)
  • (modified) openmp/runtime/test/CMakeLists.txt (-1)
  • (modified) openmp/runtime/test/lit.cfg (-3)
  • (modified) openmp/runtime/test/lit.site.cfg.in (-1)
  • (modified) openmp/runtime/test/tasking/omp_record_replay.cpp (+2-5)
  • (modified) openmp/runtime/test/tasking/omp_record_replay_deps.cpp (+2-5)
  • (modified) openmp/runtime/test/tasking/omp_record_replay_multiTDGs.cpp (+4-8)
  • (modified) openmp/runtime/test/tasking/omp_record_replay_print_dot.cpp (+4-8)
  • (modified) openmp/runtime/test/tasking/omp_record_replay_taskloop.cpp (+2-5)
diff --git a/clang/include/clang-c/Index.h b/clang/include/clang-c/Index.h
index 1b91feabd584c50..ce5688b82920255 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 d4146d52893ffb1..49fe2ea4070bddf 100644
--- a/clang/include/clang/AST/RecursiveASTVisitor.h
+++ b/clang/include/clang/AST/RecursiveASTVisitor.h
@@ -3027,6 +3027,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 178761bdcf4d5e3..f96715abeb58105 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<
@@ -1400,6 +1402,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 72e8df8c793a7b6..d4e30368a985780 100644
--- a/clang/include/clang/Basic/TokenKinds.def
+++ b/clang/include/clang/Basic/TokenKinds.def
@@ -937,10 +937,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 f599b8b98d031fb..e8c014dfd0bf7a0 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;
@@ -2894,7 +2895,8 @@ class Parser : public CodeCompletionHandler {
   }
 
   void ParseOpenMPAttributeArgs(IdentifierInfo *AttrName,
-                                CachedTokens &OpenMPTokens);
+                                CachedTokens &OpenMPTokens,
+                                bool isOpenMPExtension);
 
   void ParseCXX11AttributeSpecifierInternal(ParsedAttributes &Attrs,
                                             CachedTokens &OpenMPTokens,
@@ -3400,6 +3402,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 47379e00a7445e3..9ef6d2a7c9ca442 100644
--- a/clang/include/clang/Sema/Sema.h
+++ b/clang/include/clang/Sema/Sema.h
@@ -11651,6 +11651,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 9e115f2a5cce3f9..b6cab03730d284e 100644
--- a/clang/include/clang/Serialization/ASTBitCodes.h
+++ b/clang/include/clang/Serialization/ASTBitCodes.h
@@ -1954,6 +1954,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 27f71edd6f99b32..1fd98118c8eaab0 100644
--- a/clang/lib/AST/StmtProfile.cpp
+++ b/clang/lib/AST/StmtProfile.cpp
@@ -1054,6 +1054,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 92b7c8d4aa546f0..fad9c70a935f672 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 {
@@ -5779,6 +5801,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,
@@ -6192,6 +6256,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:
@@ -8955,6 +9020,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:
@@ -9814,6 +9880,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:
@@ -10419,6 +10486,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:
@@ -12156,6 +12224,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 74b528d6cd7f8cc..3a81852c5c3596a 100644
--- a/clang/lib/CodeGen/CGOpenMPRuntime.h
+++ b/clang/lib/CodeGen/CGOpenMPRuntime.h
@@ -1332,6 +1332,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.
@@ -2137,6 +2141,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 93819ab815add08..6c14dd918333266 100644
--- a/clang/lib/CodeGen/CGOpenMPRuntimeGPU.cpp
+++ b/clang/lib/CodeGen/CGOpenMPRuntimeGPU.cpp
@@ -618,6 +618,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:
@@ -701,6 +702,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 6674aa2409a5947..0ca1e159ce38e09 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:
     EmitOMPTaskgroup...
[truncated]

clang/include/clang/AST/StmtOpenMP.h Outdated Show resolved Hide resolved
clang/include/clang/Basic/DiagnosticParseKinds.td Outdated Show resolved Hide resolved
clang/include/clang/Basic/DiagnosticParseKinds.td Outdated Show resolved Hide resolved
clang/lib/CodeGen/CGOpenMPRuntime.cpp Show resolved Hide resolved
clang/lib/CodeGen/CGOpenMPRuntime.cpp Show resolved Hide resolved
clang/lib/CodeGen/CGOpenMPRuntime.cpp Show resolved Hide resolved
Comment on lines +940 to +947
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)
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Try to reuse the existing tokens

Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I implemented this part, but I couldn't find a way to reuse the tokens and maintain independence. We need to differentiate if it is an extension or not. What do you suggest we do to reuse a token and check if it is omp or ompx?

clang/lib/Parse/ParseOpenMP.cpp Outdated Show resolved Hide resolved
@shiltian
Copy link
Contributor

Since that is an extension, we have to check getLangOpts().OpenMPExtensions.

@@ -347,10 +347,6 @@ if(LIBOMP_OMPD_SUPPORT AND ((NOT LIBOMP_OMPT_SUPPORT) OR (NOT "${CMAKE_SYSTEM_NA
set(LIBOMP_OMPD_SUPPORT FALSE)
endif()

# OMPX Taskgraph support
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I'm not sure if I asked it before, but if possible can we run some task benchmark suites, like BOLT, to see the overhead? If no overhead, it'd be great to remove the macro.

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Sure, do you know where can we find the BOLT benchmark suite? Thanks!

Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

The easiest one off the top of my head is SPEC OMP 2012.

@josemonsalve2
Copy link
Contributor

@jdoerfert ping

@shiltian
Copy link
Contributor

Waiting for the evaluation, if possible

@josemonsalve2
Copy link
Contributor

josemonsalve2 commented Oct 24, 2023

Waiting for the evaluation, if possible

Thanks Shilei, Chenle is working on the evaluation.

The one aspect that we are still not sure what to do about is if we should split this up into multiple PRs or not.

@shiltian
Copy link
Contributor

I'd prefer to split it into at least one front end and one runtime, both with proper tests.

@josemonsalve2
Copy link
Contributor

My concern is how to split it up is I do not know a set of features that can work independently to each other. We can add the ompx infrastructure in one, but it won't be used by anything in that PR. Will that be ok?

@shiltian
Copy link
Contributor

By "ompx infrastructure" do you mean the frond end code?

@josemonsalve2
Copy link
Contributor

I mean front end code minus the taskgraph directive part. Just the part that allows for ompx to be used.

If we include the taskgraph, then it will generate code that cannot be linked. So it would be a PR that will not work for programs.

@shiltian
Copy link
Contributor

It's fine that it will generate code that cannot be linked, as long as we don't have runtime use. We just need to check generated IR.

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.
@llvmbot llvmbot added the clang:openmp OpenMP related changes to Clang label Nov 5, 2023
@josemonsalve2
Copy link
Contributor

This patch is now only for the front end. @shiltian @alexey-bataev, let us know what you think about landing just this. We are going to push another PR with the runtime changes, and that one will include numbers for performance.

@alexey-bataev
Copy link
Member

This patch is now only for the front end. @shiltian @alexey-bataev, let us know what you think about landing just this. We are going to push another PR with the runtime changes, and that one will include numbers for performance.

Not all my previous comments were addressed/answered

@josemonsalve2
Copy link
Contributor

Sorry, @alexey-bataev, some were marked as resolved, and we did not see them.

The wording on my previous question needed to be corrected, too. I did not mean to ask if this is ready to land as is but instead if the division of the original PR into just this front-end part is what you would suggest we do.

@alexey-bataev
Copy link
Member

Sorry, @alexey-bataev, some were marked as resolved, and we did not see them.

The wording on my previous question needed to be corrected, too. I did not mean to ask if this is ready to land as is but instead if the division of the original PR into just this front-end part is what you would suggest we do.

Yes, this is what suggest

Comment on lines +2559 to +2561
} else if (!getLangOpts().OpenMPExtensions) {
Diag(Loc, diag::warn_omp_extension_directive_not_enabled)
<< getOpenMPDirectiveName(DKind);
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I rather doubt there should be this check, better to enable ompx pragma handler only if getLangOpts().OpenMPExtensions is true.

Comment on lines +181 to +192
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;
};

Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Why existing openmp handlers cannot be reused?

@mikerice1969
Copy link
Contributor

Hi @josemonsalve2 if you want to help move this along it would be best to break this into at least three separate PRs.

  1. Parsing/Sema/Serialization
  2. CodeGen
  3. Extension checking framework

In whatever order makes sense to you.
We've added several extension directives in our downstream so I should be able to help here if you can break these up a bit.

@josemonsalve2
Copy link
Contributor

josemonsalve2 commented Feb 28, 2024 via email

@TerryLWilmarth
Copy link
Contributor

This patch is now only for the front end. @shiltian @alexey-bataev, let us know what you think about landing just this. We are going to push another PR with the runtime changes, and that one will include numbers for performance.

Hi! Can someone post a link here to the PR for the OMP runtime changes? Thanks!

@Munesanz
Copy link
Contributor Author

Munesanz commented Mar 1, 2024

This patch is now only for the front end. @shiltian @alexey-bataev, let us know what you think about landing just this. We are going to push another PR with the runtime changes, and that one will include numbers for performance.

Hi! Can someone post a link here to the PR for the OMP runtime changes? Thanks!

Hi! This PR initially contained both frontend and runtime changes. However the runtime changes were reverted for easier review. The PR for runtime is not created yet, but you can find all the initial changes (frontend+runtime) in the first commit of this PR:[] 5314fbb)

The record and replay mechanism commit is: (36d4e4c)

We will now split this frontend PR in several ones, as @mikerice1969 suggested, and later create the runtime PR.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
clang:codegen clang:frontend Language frontend issues, e.g. anything involving "Sema" clang:modules C++20 modules and Clang Header Modules clang:openmp OpenMP related changes to Clang clang:static analyzer clang Clang issues not falling into any other category flang:openmp openmp
Projects
None yet
Development

Successfully merging this pull request may close these issues.

7 participants