https://github.com/loopacino updated 
https://github.com/llvm/llvm-project/pull/206977

>From 0fb5bd42f1e127faea963c359b1e3c69cb969c60 Mon Sep 17 00:00:00 2001
From: amtiwari <[email protected]>
Date: Wed, 1 Jul 2026 09:06:58 -0400
Subject: [PATCH 1/9] add OMPFlattenDirective ast node

---
 clang/include/clang/AST/RecursiveASTVisitor.h |  3 +
 clang/include/clang/AST/StmtOpenMP.h          | 75 ++++++++++++++++++-
 clang/include/clang/Basic/StmtNodes.td        |  1 +
 clang/lib/AST/StmtOpenMP.cpp                  | 20 +++++
 clang/lib/AST/StmtPrinter.cpp                 |  5 ++
 clang/lib/AST/StmtProfile.cpp                 |  4 +
 clang/lib/Basic/OpenMPKinds.cpp               |  2 +-
 7 files changed, 108 insertions(+), 2 deletions(-)

diff --git a/clang/include/clang/AST/RecursiveASTVisitor.h 
b/clang/include/clang/AST/RecursiveASTVisitor.h
index b000a34043696..e425f7a31f59c 100644
--- a/clang/include/clang/AST/RecursiveASTVisitor.h
+++ b/clang/include/clang/AST/RecursiveASTVisitor.h
@@ -3227,6 +3227,9 @@ DEF_TRAVERSE_STMT(OMPFuseDirective,
 DEF_TRAVERSE_STMT(OMPInterchangeDirective,
                   { TRY_TO(TraverseOMPExecutableDirective(S)); })
 
+DEF_TRAVERSE_STMT(OMPFlattenDirective,
+                  { TRY_TO(TraverseOMPExecutableDirective(S)); })
+
 DEF_TRAVERSE_STMT(OMPSplitDirective,
                   { TRY_TO(TraverseOMPExecutableDirective(S)); })
 
diff --git a/clang/include/clang/AST/StmtOpenMP.h 
b/clang/include/clang/AST/StmtOpenMP.h
index dbc76e7df8ecd..1420331f37c1f 100644
--- a/clang/include/clang/AST/StmtOpenMP.h
+++ b/clang/include/clang/AST/StmtOpenMP.h
@@ -1041,7 +1041,7 @@ class OMPCanonicalLoopNestTransformationDirective
     Stmt::StmtClass C = T->getStmtClass();
     return C == OMPTileDirectiveClass || C == OMPUnrollDirectiveClass ||
            C == OMPReverseDirectiveClass || C == OMPInterchangeDirectiveClass 
||
-           C == OMPStripeDirectiveClass;
+           C == OMPStripeDirectiveClass || C == OMPFlattenDirectiveClass;
   }
 };
 
@@ -5959,6 +5959,79 @@ class OMPInterchangeDirective final
   }
 };
 
+/// Represents the '#pragma omp flatten' loop transformation directive.
+///
+/// \code{c}
+///   #pragma omp flatten
+///   for (int i = 0; i < m; ++i)
+///     for (int j = 0; j < n; ++j)
+///       ..
+/// \endcode
+class OMPFlattenDirective final
+    : public OMPCanonicalLoopNestTransformationDirective {
+  friend class ASTStmtReader;
+  friend class OMPExecutableDirective;
+
+  /// Offsets of child members.
+  enum {
+    PreInitsOffset = 0,
+    TransformedStmtOffset,
+  };
+
+  explicit OMPFlattenDirective(SourceLocation StartLoc, SourceLocation EndLoc,
+                               unsigned NumLoops)
+      : OMPCanonicalLoopNestTransformationDirective(
+            OMPFlattenDirectiveClass, llvm::omp::OMPD_flatten, StartLoc, 
EndLoc,
+            NumLoops) {}
+
+  void setPreInits(Stmt *PreInits) {
+    Data->getChildren()[PreInitsOffset] = PreInits;
+  }
+
+  void setTransformedStmt(Stmt *S) {
+    Data->getChildren()[TransformedStmtOffset] = S;
+  }
+
+public:
+  /// Create a new AST node representation for '#pragma omp flatten'.
+  ///
+  /// \param C         Context of the AST.
+  /// \param StartLoc  Location of the introducer (e.g. the 'omp' token).
+  /// \param EndLoc    Location of the directive's end (e.g. the tok::eod).
+  /// \param Clauses   The directive's clauses.
+  /// \param NumLoops  Number of affected loops (the flatten depth, currently
+  ///                  always 2).
+  /// \param AssociatedStmt  The outermost associated loop.
+  /// \param TransformedStmt The flattened loop, or nullptr in dependent
+  ///                        contexts.
+  /// \param PreInits  Helper preinits statements for the loop nest.
+  static OMPFlattenDirective *
+  Create(const ASTContext &C, SourceLocation StartLoc, SourceLocation EndLoc,
+         ArrayRef<OMPClause *> Clauses, unsigned NumLoops, Stmt 
*AssociatedStmt,
+         Stmt *TransformedStmt, Stmt *PreInits);
+
+  /// Build an empty '#pragma omp flatten' AST node for deserialization.
+  ///
+  /// \param C          Context of the AST.
+  /// \param NumClauses Number of clauses to allocate.
+  /// \param NumLoops   Number of associated loops to allocate.
+  static OMPFlattenDirective *
+  CreateEmpty(const ASTContext &C, unsigned NumClauses, unsigned NumLoops);
+
+  /// Gets the flattened loop after the transformation. This is the de-sugared
+  /// replacement or nullptr in dependent contexts.
+  Stmt *getTransformedStmt() const {
+    return Data->getChildren()[TransformedStmtOffset];
+  }
+
+  /// Return preinits statement.
+  Stmt *getPreInits() const { return Data->getChildren()[PreInitsOffset]; }
+
+  static bool classof(const Stmt *T) {
+    return T->getStmtClass() == OMPFlattenDirectiveClass;
+  }
+};
+
 /// The base class for all transformation directives of canonical loop
 /// sequences (currently only 'fuse')
 class OMPCanonicalLoopSequenceTransformationDirective
diff --git a/clang/include/clang/Basic/StmtNodes.td 
b/clang/include/clang/Basic/StmtNodes.td
index e166894ea024b..0d7a0c1490a1e 100644
--- a/clang/include/clang/Basic/StmtNodes.td
+++ b/clang/include/clang/Basic/StmtNodes.td
@@ -247,6 +247,7 @@ def OMPReverseDirective : 
StmtNode<OMPCanonicalLoopNestTransformationDirective>;
 def OMPSplitDirective : StmtNode<OMPCanonicalLoopNestTransformationDirective>;
 def OMPInterchangeDirective
     : StmtNode<OMPCanonicalLoopNestTransformationDirective>;
+def OMPFlattenDirective : 
StmtNode<OMPCanonicalLoopNestTransformationDirective>;
 def OMPCanonicalLoopSequenceTransformationDirective
     : StmtNode<OMPExecutableDirective, 1>;
 def OMPFuseDirective
diff --git a/clang/lib/AST/StmtOpenMP.cpp b/clang/lib/AST/StmtOpenMP.cpp
index 9d6b315effb41..477604ef3dafb 100644
--- a/clang/lib/AST/StmtOpenMP.cpp
+++ b/clang/lib/AST/StmtOpenMP.cpp
@@ -552,6 +552,26 @@ OMPInterchangeDirective::CreateEmpty(const ASTContext &C, 
unsigned NumClauses,
       SourceLocation(), SourceLocation(), NumLoops);
 }
 
+OMPFlattenDirective *OMPFlattenDirective::Create(
+    const ASTContext &C, SourceLocation StartLoc, SourceLocation EndLoc,
+    ArrayRef<OMPClause *> Clauses, unsigned NumLoops, Stmt *AssociatedStmt,
+    Stmt *TransformedStmt, Stmt *PreInits) {
+  OMPFlattenDirective *Dir = createDirective<OMPFlattenDirective>(
+      C, Clauses, AssociatedStmt, TransformedStmtOffset + 1, StartLoc, EndLoc,
+      NumLoops);
+  Dir->setTransformedStmt(TransformedStmt);
+  Dir->setPreInits(PreInits);
+  return Dir;
+}
+
+OMPFlattenDirective *OMPFlattenDirective::CreateEmpty(const ASTContext &C,
+                                                      unsigned NumClauses,
+                                                      unsigned NumLoops) {
+  return createEmptyDirective<OMPFlattenDirective>(
+      C, NumClauses, /*HasAssociatedStmt=*/true, TransformedStmtOffset + 1,
+      SourceLocation(), SourceLocation(), NumLoops);
+}
+
 OMPSplitDirective *
 OMPSplitDirective::Create(const ASTContext &C, SourceLocation StartLoc,
                           SourceLocation EndLoc, ArrayRef<OMPClause *> Clauses,
diff --git a/clang/lib/AST/StmtPrinter.cpp b/clang/lib/AST/StmtPrinter.cpp
index 6c3294573e9d4..0bacb79ed86e3 100644
--- a/clang/lib/AST/StmtPrinter.cpp
+++ b/clang/lib/AST/StmtPrinter.cpp
@@ -800,6 +800,11 @@ void 
StmtPrinter::VisitOMPInterchangeDirective(OMPInterchangeDirective *Node) {
   PrintOMPExecutableDirective(Node);
 }
 
+void StmtPrinter::VisitOMPFlattenDirective(OMPFlattenDirective *Node) {
+  Indent() << "#pragma omp flatten";
+  PrintOMPExecutableDirective(Node);
+}
+
 void StmtPrinter::VisitOMPSplitDirective(OMPSplitDirective *Node) {
   Indent() << "#pragma omp split";
   PrintOMPExecutableDirective(Node);
diff --git a/clang/lib/AST/StmtProfile.cpp b/clang/lib/AST/StmtProfile.cpp
index 90eab530e0c2e..de7ed322d7424 100644
--- a/clang/lib/AST/StmtProfile.cpp
+++ b/clang/lib/AST/StmtProfile.cpp
@@ -1071,6 +1071,10 @@ void StmtProfiler::VisitOMPInterchangeDirective(
   VisitOMPCanonicalLoopNestTransformationDirective(S);
 }
 
+void StmtProfiler::VisitOMPFlattenDirective(const OMPFlattenDirective *S) {
+  VisitOMPCanonicalLoopNestTransformationDirective(S);
+}
+
 void StmtProfiler::VisitOMPSplitDirective(const OMPSplitDirective *S) {
   VisitOMPCanonicalLoopNestTransformationDirective(S);
 }
diff --git a/clang/lib/Basic/OpenMPKinds.cpp b/clang/lib/Basic/OpenMPKinds.cpp
index 675d86349c933..57e0347f8ea77 100644
--- a/clang/lib/Basic/OpenMPKinds.cpp
+++ b/clang/lib/Basic/OpenMPKinds.cpp
@@ -818,7 +818,7 @@ bool 
clang::isOpenMPCanonicalLoopNestTransformationDirective(
     OpenMPDirectiveKind DKind) {
   return DKind == OMPD_tile || DKind == OMPD_unroll || DKind == OMPD_reverse ||
          DKind == OMPD_split || DKind == OMPD_interchange ||
-         DKind == OMPD_stripe;
+         DKind == OMPD_stripe || DKind == OMPD_flatten;
 }
 
 bool clang::isOpenMPCanonicalLoopSequenceTransformationDirective(

>From 933007b6333584fb358adc4f89a61db1ae15d4cb Mon Sep 17 00:00:00 2001
From: amtiwari <[email protected]>
Date: Wed, 8 Jul 2026 16:02:27 -0400
Subject: [PATCH 2/9] add OMPDepthClause ast node

---
 clang/include/clang/AST/OpenMPClause.h        | 68 +++++++++++++++++++
 clang/include/clang/AST/RecursiveASTVisitor.h |  6 ++
 clang/lib/AST/OpenMPClause.cpp                | 25 +++++++
 clang/lib/AST/StmtProfile.cpp                 |  5 ++
 clang/lib/Parse/ParseOpenMP.cpp               |  1 +
 llvm/include/llvm/Frontend/OpenMP/OMP.td      |  1 +
 6 files changed, 106 insertions(+)

diff --git a/clang/include/clang/AST/OpenMPClause.h 
b/clang/include/clang/AST/OpenMPClause.h
index 8ceafc4669297..50d1364a9726d 100644
--- a/clang/include/clang/AST/OpenMPClause.h
+++ b/clang/include/clang/AST/OpenMPClause.h
@@ -1380,6 +1380,74 @@ class OMPPartialClause final : public OMPClause {
   }
 };
 
+/// This represents the 'depth' clause on the '#pragma omp flatten' (and
+/// '#pragma omp fuse') loop-transformation directives.
+///
+/// \code
+/// #pragma omp flatten depth(3)
+/// \endcode
+/// In this example the 'flatten' directive has a 'depth' clause whose argument
+/// '3' specifies how many perfectly nested loops are combined into one.
+/// The argument must be a positive integer constant expression that evaluates
+/// to at most the loop nest depth of the associated loop nest.
+class OMPDepthClause final : public OMPClause {
+  friend class OMPClauseReader;
+
+  /// Location of '('.
+  SourceLocation LParenLoc;
+
+  /// The depth expression (number of loops to flatten).
+  Stmt *Depth = nullptr;
+
+  /// Build an empty clause.
+  explicit OMPDepthClause() : OMPClause(llvm::omp::OMPC_depth, {}, {}) {}
+
+  /// Set the depth expression.
+  void setDepth(Expr *E) { Depth = E; }
+
+  /// Sets the location of '('.
+  void setLParenLoc(SourceLocation Loc) { LParenLoc = Loc; }
+
+public:
+  /// Build an AST node for a 'depth' clause.
+  ///
+  /// \param C         Context of the AST.
+  /// \param StartLoc  Location of the 'depth' identifier.
+  /// \param LParenLoc Location of '('.
+  /// \param EndLoc    Location of ')'.
+  /// \param Depth     The depth expression.
+  static OMPDepthClause *Create(const ASTContext &C, SourceLocation StartLoc,
+                                SourceLocation LParenLoc, SourceLocation 
EndLoc,
+                                Expr *Depth);
+
+  /// Build an empty 'depth' AST node for deserialization.
+  ///
+  /// \param C     Context of the AST.
+  static OMPDepthClause *CreateEmpty(const ASTContext &C);
+
+  /// Returns the location of '('.
+  SourceLocation getLParenLoc() const { return LParenLoc; }
+
+  /// Returns the depth expression or nullptr if not set.
+  Expr *getDepth() const { return cast_or_null<Expr>(Depth); }
+
+  child_range children() { return child_range(&Depth, &Depth + 1); }
+  const_child_range children() const {
+    return const_child_range(&Depth, &Depth + 1);
+  }
+
+  child_range used_children() {
+    return child_range(child_iterator(), child_iterator());
+  }
+  const_child_range used_children() const {
+    return const_child_range(const_child_iterator(), const_child_iterator());
+  }
+
+  static bool classof(const OMPClause *T) {
+    return T->getClauseKind() == llvm::omp::OMPC_depth;
+  }
+};
+
 /// This represents 'collapse' clause in the '#pragma omp ...'
 /// directive.
 ///
diff --git a/clang/include/clang/AST/RecursiveASTVisitor.h 
b/clang/include/clang/AST/RecursiveASTVisitor.h
index e425f7a31f59c..da55e97fdfcb5 100644
--- a/clang/include/clang/AST/RecursiveASTVisitor.h
+++ b/clang/include/clang/AST/RecursiveASTVisitor.h
@@ -3568,6 +3568,12 @@ bool 
RecursiveASTVisitor<Derived>::VisitOMPPartialClause(OMPPartialClause *C) {
   return true;
 }
 
+template <typename Derived>
+bool RecursiveASTVisitor<Derived>::VisitOMPDepthClause(OMPDepthClause *C) {
+  TRY_TO(TraverseStmt(C->getDepth()));
+  return true;
+}
+
 template <typename Derived>
 bool
 RecursiveASTVisitor<Derived>::VisitOMPCollapseClause(OMPCollapseClause *C) {
diff --git a/clang/lib/AST/OpenMPClause.cpp b/clang/lib/AST/OpenMPClause.cpp
index ed00e80144c25..7b2f67a31cad9 100644
--- a/clang/lib/AST/OpenMPClause.cpp
+++ b/clang/lib/AST/OpenMPClause.cpp
@@ -1057,6 +1057,22 @@ OMPPartialClause *OMPPartialClause::CreateEmpty(const 
ASTContext &C) {
   return new (C) OMPPartialClause();
 }
 
+OMPDepthClause *OMPDepthClause::Create(const ASTContext &C,
+                                       SourceLocation StartLoc,
+                                       SourceLocation LParenLoc,
+                                       SourceLocation EndLoc, Expr *Depth) {
+  OMPDepthClause *Clause = CreateEmpty(C);
+  Clause->setLocStart(StartLoc);
+  Clause->setLParenLoc(LParenLoc);
+  Clause->setLocEnd(EndLoc);
+  Clause->setDepth(Depth);
+  return Clause;
+}
+
+OMPDepthClause *OMPDepthClause::CreateEmpty(const ASTContext &C) {
+  return new (C) OMPDepthClause();
+}
+
 OMPLoopRangeClause *
 OMPLoopRangeClause::Create(const ASTContext &C, SourceLocation StartLoc,
                            SourceLocation LParenLoc, SourceLocation FirstLoc,
@@ -2069,6 +2085,15 @@ void 
OMPClausePrinter::VisitOMPPermutationClause(OMPPermutationClause *Node) {
 
 void OMPClausePrinter::VisitOMPFullClause(OMPFullClause *Node) { OS << "full"; 
}
 
+void OMPClausePrinter::VisitOMPDepthClause(OMPDepthClause *Node) {
+  OS << "depth";
+  if (Expr *Depth = Node->getDepth()) {
+    OS << '(';
+    Depth->printPretty(OS, nullptr, Policy, 0);
+    OS << ')';
+  }
+}
+
 void OMPClausePrinter::VisitOMPPartialClause(OMPPartialClause *Node) {
   OS << "partial";
 
diff --git a/clang/lib/AST/StmtProfile.cpp b/clang/lib/AST/StmtProfile.cpp
index de7ed322d7424..838d6d02f7446 100644
--- a/clang/lib/AST/StmtProfile.cpp
+++ b/clang/lib/AST/StmtProfile.cpp
@@ -521,6 +521,11 @@ void OMPClauseProfiler::VisitOMPPartialClause(const 
OMPPartialClause *C) {
     Profiler->VisitExpr(Factor);
 }
 
+void OMPClauseProfiler::VisitOMPDepthClause(const OMPDepthClause *C) {
+  if (const Expr *Depth = C->getDepth())
+    Profiler->VisitExpr(Depth);
+}
+
 void OMPClauseProfiler::VisitOMPLoopRangeClause(const OMPLoopRangeClause *C) {
   if (const Expr *First = C->getFirst())
     Profiler->VisitExpr(First);
diff --git a/clang/lib/Parse/ParseOpenMP.cpp b/clang/lib/Parse/ParseOpenMP.cpp
index af52295df2d8b..952a517205381 100644
--- a/clang/lib/Parse/ParseOpenMP.cpp
+++ b/clang/lib/Parse/ParseOpenMP.cpp
@@ -3247,6 +3247,7 @@ OMPClause *Parser::ParseOpenMPClause(OpenMPDirectiveKind 
DKind,
   case OMPC_nocontext:
   case OMPC_filter:
   case OMPC_partial:
+  case OMPC_depth:
   case OMPC_align:
   case OMPC_message:
   case OMPC_ompx_dyn_cgroup_mem:
diff --git a/llvm/include/llvm/Frontend/OpenMP/OMP.td 
b/llvm/include/llvm/Frontend/OpenMP/OMP.td
index 679a944fc4358..d49c5ee1a0db3 100644
--- a/llvm/include/llvm/Frontend/OpenMP/OMP.td
+++ b/llvm/include/llvm/Frontend/OpenMP/OMP.td
@@ -161,6 +161,7 @@ def OMPC_Depobj : Clause<[Spelling<"depobj">]> {
   let isImplicit = true;
 }
 def OMPC_Depth : Clause<[Spelling<"depth">]> {
+  let clangClass = "OMPDepthClause";
   let flangClass = "ScalarIntConstantExpr";
 }
 def OMPC_Destroy : Clause<[Spelling<"destroy">]> {

>From b63024e1e342cd168ef128a3f6a24909df2a82db Mon Sep 17 00:00:00 2001
From: amtiwari <[email protected]>
Date: Wed, 8 Jul 2026 16:04:44 -0400
Subject: [PATCH 3/9] template-transform support for flatten directive & depth
 clause

---
 clang/lib/Sema/TreeTransform.h | 33 +++++++++++++++++++++++++++++++++
 1 file changed, 33 insertions(+)

diff --git a/clang/lib/Sema/TreeTransform.h b/clang/lib/Sema/TreeTransform.h
index 3b99ff4bb9e23..865622ad50f1c 100644
--- a/clang/lib/Sema/TreeTransform.h
+++ b/clang/lib/Sema/TreeTransform.h
@@ -1804,6 +1804,14 @@ class TreeTransform {
                                                        LParenLoc, EndLoc);
   }
 
+  /// Build a new OpenMP 'depth' clause.
+  OMPClause *RebuildOMPDepthClause(Expr *Depth, SourceLocation StartLoc,
+                                   SourceLocation LParenLoc,
+                                   SourceLocation EndLoc) {
+    return getSema().OpenMP().ActOnOpenMPDepthClause(Depth, StartLoc, 
LParenLoc,
+                                                     EndLoc);
+  }
+
   OMPClause *
   RebuildOMPLoopRangeClause(Expr *First, Expr *Count, SourceLocation StartLoc,
                             SourceLocation LParenLoc, SourceLocation FirstLoc,
@@ -9791,6 +9799,17 @@ 
TreeTransform<Derived>::TransformOMPSplitDirective(OMPSplitDirective *D) {
   return Res;
 }
 
+template <typename Derived>
+StmtResult
+TreeTransform<Derived>::TransformOMPFlattenDirective(OMPFlattenDirective *D) {
+  DeclarationNameInfo DirName;
+  getDerived().getSema().OpenMP().StartOpenMPDSABlock(
+      D->getDirectiveKind(), DirName, nullptr, D->getBeginLoc());
+  StmtResult Res = getDerived().TransformOMPExecutableDirective(D);
+  getDerived().getSema().OpenMP().EndOpenMPDSABlock(Res.get());
+  return Res;
+}
+
 template <typename Derived>
 StmtResult
 TreeTransform<Derived>::TransformOMPFuseDirective(OMPFuseDirective *D) {
@@ -10717,6 +10736,20 @@ 
TreeTransform<Derived>::TransformOMPPartialClause(OMPPartialClause *C) {
                                  C->getEndLoc());
 }
 
+template <typename Derived>
+OMPClause *TreeTransform<Derived>::TransformOMPDepthClause(OMPDepthClause *C) {
+  ExprResult T = getDerived().TransformExpr(C->getDepth());
+  if (T.isInvalid())
+    return nullptr;
+  Expr *Depth = T.get();
+  bool Changed = Depth != C->getDepth();
+
+  if (!Changed && !getDerived().AlwaysRebuild())
+    return C;
+  return RebuildOMPDepthClause(Depth, C->getBeginLoc(), C->getLParenLoc(),
+                               C->getEndLoc());
+}
+
 template <typename Derived>
 OMPClause *
 TreeTransform<Derived>::TransformOMPLoopRangeClause(OMPLoopRangeClause *C) {

>From deafb222a7d251069c68a44fa267e58e750f1064 Mon Sep 17 00:00:00 2001
From: amtiwari <[email protected]>
Date: Wed, 8 Jul 2026 16:08:12 -0400
Subject: [PATCH 4/9] serialize flatten

---
 clang/include/clang/Serialization/ASTBitCodes.h |  1 +
 clang/lib/Serialization/ASTReaderStmt.cpp       | 11 +++++++++++
 clang/lib/Serialization/ASTWriterStmt.cpp       |  5 +++++
 3 files changed, 17 insertions(+)

diff --git a/clang/include/clang/Serialization/ASTBitCodes.h 
b/clang/include/clang/Serialization/ASTBitCodes.h
index 279380de2f7fe..93a0e0a454b68 100644
--- a/clang/include/clang/Serialization/ASTBitCodes.h
+++ b/clang/include/clang/Serialization/ASTBitCodes.h
@@ -1970,6 +1970,7 @@ enum StmtCode {
   STMT_OMP_REVERSE_DIRECTIVE,
   STMT_OMP_SPLIT_DIRECTIVE,
   STMT_OMP_INTERCHANGE_DIRECTIVE,
+  STMT_OMP_FLATTEN_DIRECTIVE,
   STMT_OMP_FUSE_DIRECTIVE,
   STMT_OMP_FOR_DIRECTIVE,
   STMT_OMP_FOR_SIMD_DIRECTIVE,
diff --git a/clang/lib/Serialization/ASTReaderStmt.cpp 
b/clang/lib/Serialization/ASTReaderStmt.cpp
index 02ccf8d4d41c2..8c2debd6cdf32 100644
--- a/clang/lib/Serialization/ASTReaderStmt.cpp
+++ b/clang/lib/Serialization/ASTReaderStmt.cpp
@@ -2537,6 +2537,10 @@ void 
ASTStmtReader::VisitOMPInterchangeDirective(OMPInterchangeDirective *D) {
   VisitOMPCanonicalLoopNestTransformationDirective(D);
 }
 
+void ASTStmtReader::VisitOMPFlattenDirective(OMPFlattenDirective *D) {
+  VisitOMPCanonicalLoopNestTransformationDirective(D);
+}
+
 void ASTStmtReader::VisitOMPSplitDirective(OMPSplitDirective *D) {
   VisitOMPCanonicalLoopNestTransformationDirective(D);
 }
@@ -3719,6 +3723,13 @@ Stmt *ASTReader::ReadStmtFromStream(ModuleFile &F) {
       break;
     }
 
+    case STMT_OMP_FLATTEN_DIRECTIVE: {
+      unsigned NumLoops = Record[ASTStmtReader::NumStmtFields];
+      unsigned NumClauses = Record[ASTStmtReader::NumStmtFields + 1];
+      S = OMPFlattenDirective::CreateEmpty(Context, NumClauses, NumLoops);
+      break;
+    }
+
     case STMT_OMP_FOR_DIRECTIVE: {
       unsigned CollapsedNum = Record[ASTStmtReader::NumStmtFields];
       unsigned NumClauses = Record[ASTStmtReader::NumStmtFields + 1];
diff --git a/clang/lib/Serialization/ASTWriterStmt.cpp 
b/clang/lib/Serialization/ASTWriterStmt.cpp
index 4e9eadd730a56..dfe28a9b915e3 100644
--- a/clang/lib/Serialization/ASTWriterStmt.cpp
+++ b/clang/lib/Serialization/ASTWriterStmt.cpp
@@ -2547,6 +2547,11 @@ void 
ASTStmtWriter::VisitOMPInterchangeDirective(OMPInterchangeDirective *D) {
   Code = serialization::STMT_OMP_INTERCHANGE_DIRECTIVE;
 }
 
+void ASTStmtWriter::VisitOMPFlattenDirective(OMPFlattenDirective *D) {
+  VisitOMPCanonicalLoopNestTransformationDirective(D);
+  Code = serialization::STMT_OMP_FLATTEN_DIRECTIVE;
+}
+
 void ASTStmtWriter::VisitOMPSplitDirective(OMPSplitDirective *D) {
   VisitOMPCanonicalLoopNestTransformationDirective(D);
   Code = serialization::STMT_OMP_SPLIT_DIRECTIVE;

>From 3e2dfeb99230057b7cb9c484182ae33befbe1e41 Mon Sep 17 00:00:00 2001
From: amtiwari <[email protected]>
Date: Wed, 8 Jul 2026 16:09:03 -0400
Subject: [PATCH 5/9] serialize depth

---
 clang/lib/Serialization/ASTReader.cpp | 8 ++++++++
 clang/lib/Serialization/ASTWriter.cpp | 5 +++++
 2 files changed, 13 insertions(+)

diff --git a/clang/lib/Serialization/ASTReader.cpp 
b/clang/lib/Serialization/ASTReader.cpp
index f8a6a38bb9b5c..4f51d79a52105 100644
--- a/clang/lib/Serialization/ASTReader.cpp
+++ b/clang/lib/Serialization/ASTReader.cpp
@@ -11495,6 +11495,9 @@ OMPClause *OMPClauseReader::readClause() {
   case llvm::omp::OMPC_partial:
     C = OMPPartialClause::CreateEmpty(Context);
     break;
+  case llvm::omp::OMPC_depth:
+    C = OMPDepthClause::CreateEmpty(Context);
+    break;
   case llvm::omp::OMPC_looprange:
     C = OMPLoopRangeClause::CreateEmpty(Context);
     break;
@@ -11924,6 +11927,11 @@ void 
OMPClauseReader::VisitOMPPartialClause(OMPPartialClause *C) {
   C->setLParenLoc(Record.readSourceLocation());
 }
 
+void OMPClauseReader::VisitOMPDepthClause(OMPDepthClause *C) {
+  C->setDepth(Record.readSubExpr());
+  C->setLParenLoc(Record.readSourceLocation());
+}
+
 void OMPClauseReader::VisitOMPLoopRangeClause(OMPLoopRangeClause *C) {
   C->setFirst(Record.readSubExpr());
   C->setCount(Record.readSubExpr());
diff --git a/clang/lib/Serialization/ASTWriter.cpp 
b/clang/lib/Serialization/ASTWriter.cpp
index 357a7f7e95fa0..cbfeaa9e6638a 100644
--- a/clang/lib/Serialization/ASTWriter.cpp
+++ b/clang/lib/Serialization/ASTWriter.cpp
@@ -8106,6 +8106,11 @@ void 
OMPClauseWriter::VisitOMPPartialClause(OMPPartialClause *C) {
   Record.AddSourceLocation(C->getLParenLoc());
 }
 
+void OMPClauseWriter::VisitOMPDepthClause(OMPDepthClause *C) {
+  Record.AddStmt(C->getDepth());
+  Record.AddSourceLocation(C->getLParenLoc());
+}
+
 void OMPClauseWriter::VisitOMPLoopRangeClause(OMPLoopRangeClause *C) {
   Record.AddStmt(C->getFirst());
   Record.AddStmt(C->getCount());

>From 4ae746ca1eeaf11db10e859572a4500029d01cce Mon Sep 17 00:00:00 2001
From: amtiwari <[email protected]>
Date: Wed, 8 Jul 2026 16:17:29 -0400
Subject: [PATCH 6/9] add analysis traversal support for flatten directive

---
 clang/lib/Sema/SemaExceptionSpec.cpp         | 1 +
 clang/lib/StaticAnalyzer/Core/ExprEngine.cpp | 1 +
 2 files changed, 2 insertions(+)

diff --git a/clang/lib/Sema/SemaExceptionSpec.cpp 
b/clang/lib/Sema/SemaExceptionSpec.cpp
index 40d530a1f3925..995b5b6010978 100644
--- a/clang/lib/Sema/SemaExceptionSpec.cpp
+++ b/clang/lib/Sema/SemaExceptionSpec.cpp
@@ -1508,6 +1508,7 @@ CanThrowResult Sema::canThrow(const Stmt *S) {
   case Stmt::OMPUnrollDirectiveClass:
   case Stmt::OMPReverseDirectiveClass:
   case Stmt::OMPInterchangeDirectiveClass:
+  case Stmt::OMPFlattenDirectiveClass:
   case Stmt::OMPSplitDirectiveClass:
   case Stmt::OMPFuseDirectiveClass:
   case Stmt::OMPSingleDirectiveClass:
diff --git a/clang/lib/StaticAnalyzer/Core/ExprEngine.cpp 
b/clang/lib/StaticAnalyzer/Core/ExprEngine.cpp
index cfb294736ee02..3f666be00cc24 100644
--- a/clang/lib/StaticAnalyzer/Core/ExprEngine.cpp
+++ b/clang/lib/StaticAnalyzer/Core/ExprEngine.cpp
@@ -1783,6 +1783,7 @@ void ExprEngine::Visit(const Stmt *S, ExplodedNode *Pred,
     case Stmt::OMPStripeDirectiveClass:
     case Stmt::OMPTileDirectiveClass:
     case Stmt::OMPInterchangeDirectiveClass:
+    case Stmt::OMPFlattenDirectiveClass:
     case Stmt::OMPSplitDirectiveClass:
     case Stmt::OMPFuseDirectiveClass:
     case Stmt::OMPInteropDirectiveClass:

>From 415eba88ad0af63c552b4c5c2eabd660bcb29c02 Mon Sep 17 00:00:00 2001
From: amtiwari <[email protected]>
Date: Wed, 8 Jul 2026 16:21:25 -0400
Subject: [PATCH 7/9] codegen flatten directive

---
 clang/lib/CodeGen/CGStmt.cpp        | 3 +++
 clang/lib/CodeGen/CGStmtOpenMP.cpp  | 8 ++++++++
 clang/lib/CodeGen/CodeGenFunction.h | 1 +
 3 files changed, 12 insertions(+)

diff --git a/clang/lib/CodeGen/CGStmt.cpp b/clang/lib/CodeGen/CGStmt.cpp
index 232094777f233..27f48cb63b553 100644
--- a/clang/lib/CodeGen/CGStmt.cpp
+++ b/clang/lib/CodeGen/CGStmt.cpp
@@ -236,6 +236,9 @@ void CodeGenFunction::EmitStmt(const Stmt *S, 
ArrayRef<const Attr *> Attrs) {
   case Stmt::OMPInterchangeDirectiveClass:
     EmitOMPInterchangeDirective(cast<OMPInterchangeDirective>(*S));
     break;
+  case Stmt::OMPFlattenDirectiveClass:
+    EmitOMPFlattenDirective(cast<OMPFlattenDirective>(*S));
+    break;
   case Stmt::OMPFuseDirectiveClass:
     EmitOMPFuseDirective(cast<OMPFuseDirective>(*S));
     break;
diff --git a/clang/lib/CodeGen/CGStmtOpenMP.cpp 
b/clang/lib/CodeGen/CGStmtOpenMP.cpp
index 95fd6694437fe..25da3430a23fe 100644
--- a/clang/lib/CodeGen/CGStmtOpenMP.cpp
+++ b/clang/lib/CodeGen/CGStmtOpenMP.cpp
@@ -218,6 +218,8 @@ class OMPLoopScope : public 
CodeGenFunction::RunCleanupsScope {
     } else if (const auto *Interchange =
                    dyn_cast<OMPInterchangeDirective>(&S)) {
       PreInits = Interchange->getPreInits();
+    } else if (const auto *Flatten = dyn_cast<OMPFlattenDirective>(&S)) {
+      PreInits = Flatten->getPreInits();
     } else {
       llvm_unreachable("Unknown loop-based directive kind.");
     }
@@ -3248,6 +3250,12 @@ void CodeGenFunction::EmitOMPInterchangeDirective(
   EmitStmt(S.getTransformedStmt());
 }
 
+void CodeGenFunction::EmitOMPFlattenDirective(const OMPFlattenDirective &S) {
+  // Emit the de-sugared statement.
+  OMPTransformDirectiveScopeRAII FlattenScope(*this, &S);
+  EmitStmt(S.getTransformedStmt());
+}
+
 void CodeGenFunction::EmitOMPFuseDirective(const OMPFuseDirective &S) {
   // Emit the de-sugared statement
   OMPTransformDirectiveScopeRAII FuseScope(*this, &S);
diff --git a/clang/lib/CodeGen/CodeGenFunction.h 
b/clang/lib/CodeGen/CodeGenFunction.h
index 6d0718c243812..eea0163422cd3 100644
--- a/clang/lib/CodeGen/CodeGenFunction.h
+++ b/clang/lib/CodeGen/CodeGenFunction.h
@@ -3934,6 +3934,7 @@ class CodeGenFunction : public CodeGenTypeCache {
   void EmitOMPReverseDirective(const OMPReverseDirective &S);
   void EmitOMPSplitDirective(const OMPSplitDirective &S);
   void EmitOMPInterchangeDirective(const OMPInterchangeDirective &S);
+  void EmitOMPFlattenDirective(const OMPFlattenDirective &S);
   void EmitOMPFuseDirective(const OMPFuseDirective &S);
   void EmitOMPForDirective(const OMPForDirective &S);
   void EmitOMPForSimdDirective(const OMPForSimdDirective &S);

>From 814e2e9fe9bf4e28e4557999fbc16beec144cc39 Mon Sep 17 00:00:00 2001
From: amtiwari <[email protected]>
Date: Wed, 8 Jul 2026 16:24:42 -0400
Subject: [PATCH 8/9] add NYI CIR stub

---
 clang/lib/CIR/CodeGen/CIRGenFunction.h     | 1 +
 clang/lib/CIR/CodeGen/CIRGenStmt.cpp       | 2 ++
 clang/lib/CIR/CodeGen/CIRGenStmtOpenMP.cpp | 5 +++++
 3 files changed, 8 insertions(+)

diff --git a/clang/lib/CIR/CodeGen/CIRGenFunction.h 
b/clang/lib/CIR/CodeGen/CIRGenFunction.h
index 322355fde3957..8374583ffd4d0 100644
--- a/clang/lib/CIR/CodeGen/CIRGenFunction.h
+++ b/clang/lib/CIR/CodeGen/CIRGenFunction.h
@@ -2559,6 +2559,7 @@ class CIRGenFunction : public CIRGenTypeCache {
   mlir::LogicalResult emitOMPSplitDirective(const OMPSplitDirective &s);
   mlir::LogicalResult
   emitOMPInterchangeDirective(const OMPInterchangeDirective &s);
+  mlir::LogicalResult emitOMPFlattenDirective(const OMPFlattenDirective &s);
   mlir::LogicalResult emitOMPAssumeDirective(const OMPAssumeDirective &s);
   mlir::LogicalResult emitOMPMaskedDirective(const OMPMaskedDirective &s);
   mlir::LogicalResult emitOMPStripeDirective(const OMPStripeDirective &s);
diff --git a/clang/lib/CIR/CodeGen/CIRGenStmt.cpp 
b/clang/lib/CIR/CodeGen/CIRGenStmt.cpp
index d3acac5801e74..33d425b22d61a 100644
--- a/clang/lib/CIR/CodeGen/CIRGenStmt.cpp
+++ b/clang/lib/CIR/CodeGen/CIRGenStmt.cpp
@@ -408,6 +408,8 @@ mlir::LogicalResult CIRGenFunction::emitStmt(const Stmt *s,
     return emitOMPSplitDirective(cast<OMPSplitDirective>(*s));
   case Stmt::OMPInterchangeDirectiveClass:
     return emitOMPInterchangeDirective(cast<OMPInterchangeDirective>(*s));
+  case Stmt::OMPFlattenDirectiveClass:
+    return emitOMPFlattenDirective(cast<OMPFlattenDirective>(*s));
   case Stmt::OMPAssumeDirectiveClass:
     return emitOMPAssumeDirective(cast<OMPAssumeDirective>(*s));
   case Stmt::OMPMaskedDirectiveClass:
diff --git a/clang/lib/CIR/CodeGen/CIRGenStmtOpenMP.cpp 
b/clang/lib/CIR/CodeGen/CIRGenStmtOpenMP.cpp
index 17a1fb8090f5c..4fffd17b25a16 100644
--- a/clang/lib/CIR/CodeGen/CIRGenStmtOpenMP.cpp
+++ b/clang/lib/CIR/CodeGen/CIRGenStmtOpenMP.cpp
@@ -587,6 +587,11 @@ CIRGenFunction::emitOMPInterchangeDirective(const 
OMPInterchangeDirective &s) {
   return mlir::failure();
 }
 mlir::LogicalResult
+CIRGenFunction::emitOMPFlattenDirective(const OMPFlattenDirective &s) {
+  getCIRGenModule().errorNYI(s.getSourceRange(), "OpenMP OMPFlattenDirective");
+  return mlir::failure();
+}
+mlir::LogicalResult
 CIRGenFunction::emitOMPAssumeDirective(const OMPAssumeDirective &s) {
   getCIRGenModule().errorNYI(s.getSourceRange(), "OpenMP OMPAssumeDirective");
   return mlir::failure();

>From 0027ec6ab982a83766bd65f3e1bc45d9a671fc62 Mon Sep 17 00:00:00 2001
From: amtiwari <[email protected]>
Date: Wed, 8 Jul 2026 16:26:31 -0400
Subject: [PATCH 9/9] add libclang traversal support for depth clause

---
 clang/tools/libclang/CIndex.cpp | 4 ++++
 1 file changed, 4 insertions(+)

diff --git a/clang/tools/libclang/CIndex.cpp b/clang/tools/libclang/CIndex.cpp
index ac2fad38a1348..f8ab63e3e0dae 100644
--- a/clang/tools/libclang/CIndex.cpp
+++ b/clang/tools/libclang/CIndex.cpp
@@ -2378,6 +2378,10 @@ void OMPClauseEnqueue::VisitOMPLoopRangeClause(const 
OMPLoopRangeClause *C) {
   Visitor->AddStmt(C->getCount());
 }
 
+void OMPClauseEnqueue::VisitOMPDepthClause(const OMPDepthClause *C) {
+  Visitor->AddStmt(C->getDepth());
+}
+
 void OMPClauseEnqueue::VisitOMPAllocatorClause(const OMPAllocatorClause *C) {
   Visitor->AddStmt(C->getAllocator());
 }

_______________________________________________
cfe-commits mailing list
[email protected]
https://lists.llvm.org/cgi-bin/mailman/listinfo/cfe-commits

Reply via email to