[clang] [llvm] [Clang][OpenMP] Add `#pragma omp flatten` loop directive (PR #206977)
Amit Tiwari via cfe-commits
cfe-commits at lists.llvm.org
Thu Jul 9 06:47:11 PDT 2026
https://github.com/loopacino updated https://github.com/llvm/llvm-project/pull/206977
>From 0fb5bd42f1e127faea963c359b1e3c69cb969c60 Mon Sep 17 00:00:00 2001
From: amtiwari <amtiwari at amd.com>
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 <amtiwari at amd.com>
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 <amtiwari at amd.com>
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 <amtiwari at amd.com>
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 <amtiwari at amd.com>
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 <amtiwari at amd.com>
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 <amtiwari at amd.com>
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 <amtiwari at amd.com>
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 <amtiwari at amd.com>
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());
}
More information about the cfe-commits
mailing list