[clang] [llvm] [Clang][OpenMP] Implement Loop splitting `#pragma omp split` directive (PR #183261)
Amit Tiwari via cfe-commits
cfe-commits at lists.llvm.org
Fri Mar 13 07:22:08 PDT 2026
https://github.com/amitamd7 updated https://github.com/llvm/llvm-project/pull/183261
>From 5ee7cb284ad1e9cf98190cea04fc428b9e31ccf6 Mon Sep 17 00:00:00 2001
From: amtiwari <amtiwari at amd.com>
Date: Wed, 25 Feb 2026 03:48:23 -0500
Subject: [PATCH 1/8] Split node creation and registration
---
clang/include/clang/AST/StmtOpenMP.h | 74 +++++++++++++++++++
clang/include/clang/Basic/StmtNodes.td | 1 +
.../include/clang/Serialization/ASTBitCodes.h | 1 +
clang/lib/AST/StmtOpenMP.cpp | 22 ++++++
llvm/include/llvm/Frontend/OpenMP/OMP.td | 5 ++
5 files changed, 103 insertions(+)
diff --git a/clang/include/clang/AST/StmtOpenMP.h b/clang/include/clang/AST/StmtOpenMP.h
index bc6aeaa8d143c..626c39a7b778c 100644
--- a/clang/include/clang/AST/StmtOpenMP.h
+++ b/clang/include/clang/AST/StmtOpenMP.h
@@ -6065,6 +6065,80 @@ class OMPFuseDirective final
}
};
+/// Represents the '#pragma omp split' loop transformation directive.
+///
+/// \code{c}
+/// #pragma omp split
+/// for (int i = 0; i < n; ++i)
+/// ...
+/// \endcode
+///
+/// This directive transforms a single loop into multiple loops based on
+/// index ranges. The transformation splits the iteration space of the loop
+/// into multiple contiguous ranges.
+class OMPSplitDirective final
+ : public OMPCanonicalLoopNestTransformationDirective {
+ friend class ASTStmtReader;
+ friend class OMPExecutableDirective;
+
+ /// Offsets of child members.
+ enum {
+ PreInitsOffset = 0,
+ TransformedStmtOffset,
+ };
+
+ explicit OMPSplitDirective(SourceLocation StartLoc, SourceLocation EndLoc,
+ unsigned NumLoops)
+ : OMPCanonicalLoopNestTransformationDirective(
+ OMPSplitDirectiveClass, llvm::omp::OMPD_split, 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 split'.
+ ///
+ /// \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 NumLoops Number of affected loops (should be 1 for split).
+ /// \param AssociatedStmt The outermost associated loop.
+ /// \param TransformedStmt The loop nest after splitting, or nullptr in
+ /// dependent contexts.
+ /// \param PreInits Helper preinits statements for the loop nest.
+ static OMPSplitDirective *Create(const ASTContext &C,
+ SourceLocation StartLoc,
+ SourceLocation EndLoc,
+ Stmt *AssociatedStmt, unsigned NumLoops,
+ Stmt *TransformedStmt, Stmt *PreInits);
+
+ /// Build an empty '#pragma omp split' AST node for deserialization.
+ ///
+ /// \param C Context of the AST.
+ /// \param NumLoops Number of associated loops to allocate
+ static OMPSplitDirective *CreateEmpty(const ASTContext &C,
+ unsigned NumLoops);
+
+ /// Gets/sets the associated loops after the transformation, i.e. after
+ /// de-sugaring.
+ 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() == OMPSplitDirectiveClass;
+ }
+};
+
/// This represents '#pragma omp scan' directive.
///
/// \code
diff --git a/clang/include/clang/Basic/StmtNodes.td b/clang/include/clang/Basic/StmtNodes.td
index cb869cc210627..77db0e6d73ca3 100644
--- a/clang/include/clang/Basic/StmtNodes.td
+++ b/clang/include/clang/Basic/StmtNodes.td
@@ -242,6 +242,7 @@ def OMPTileDirective : StmtNode<OMPCanonicalLoopNestTransformationDirective>;
def OMPStripeDirective : StmtNode<OMPCanonicalLoopNestTransformationDirective>;
def OMPUnrollDirective : StmtNode<OMPCanonicalLoopNestTransformationDirective>;
def OMPReverseDirective : StmtNode<OMPCanonicalLoopNestTransformationDirective>;
+def OMPSplitDirective : StmtNode<OMPCanonicalLoopNestTransformationDirective>;
def OMPInterchangeDirective
: StmtNode<OMPCanonicalLoopNestTransformationDirective>;
def OMPCanonicalLoopSequenceTransformationDirective
diff --git a/clang/include/clang/Serialization/ASTBitCodes.h b/clang/include/clang/Serialization/ASTBitCodes.h
index d72f1f9db86b2..1786277598f8e 100644
--- a/clang/include/clang/Serialization/ASTBitCodes.h
+++ b/clang/include/clang/Serialization/ASTBitCodes.h
@@ -1959,6 +1959,7 @@ enum StmtCode {
STMP_OMP_STRIPE_DIRECTIVE,
STMT_OMP_UNROLL_DIRECTIVE,
STMT_OMP_REVERSE_DIRECTIVE,
+ STMT_OMP_SPLIT_DIRECTIVE,
STMT_OMP_INTERCHANGE_DIRECTIVE,
STMT_OMP_FUSE_DIRECTIVE,
STMT_OMP_FOR_DIRECTIVE,
diff --git a/clang/lib/AST/StmtOpenMP.cpp b/clang/lib/AST/StmtOpenMP.cpp
index a5b0cd3786a28..ada4e66b280f8 100644
--- a/clang/lib/AST/StmtOpenMP.cpp
+++ b/clang/lib/AST/StmtOpenMP.cpp
@@ -552,6 +552,28 @@ OMPInterchangeDirective::CreateEmpty(const ASTContext &C, unsigned NumClauses,
SourceLocation(), SourceLocation(), NumLoops);
}
+OMPSplitDirective *OMPSplitDirective::Create(const ASTContext &C,
+ SourceLocation StartLoc,
+ SourceLocation EndLoc,
+ Stmt *AssociatedStmt,
+ unsigned NumLoops,
+ Stmt *TransformedStmt,
+ Stmt *PreInits) {
+ OMPSplitDirective *Dir = createDirective<OMPSplitDirective>(
+ C, {}, AssociatedStmt, TransformedStmtOffset + 1, StartLoc, EndLoc,
+ NumLoops);
+ Dir->setTransformedStmt(TransformedStmt);
+ Dir->setPreInits(PreInits);
+ return Dir;
+}
+
+OMPSplitDirective *OMPSplitDirective::CreateEmpty(const ASTContext &C,
+ unsigned NumLoops) {
+ return createEmptyDirective<OMPSplitDirective>(
+ C, /*NumClauses=*/0, /*HasAssociatedStmt=*/true,
+ TransformedStmtOffset + 1, SourceLocation(), SourceLocation(), NumLoops);
+}
+
OMPFuseDirective *OMPFuseDirective::Create(
const ASTContext &C, SourceLocation StartLoc, SourceLocation EndLoc,
ArrayRef<OMPClause *> Clauses, unsigned NumGeneratedTopLevelLoops,
diff --git a/llvm/include/llvm/Frontend/OpenMP/OMP.td b/llvm/include/llvm/Frontend/OpenMP/OMP.td
index 865cad7769554..38eedd10cfdd7 100644
--- a/llvm/include/llvm/Frontend/OpenMP/OMP.td
+++ b/llvm/include/llvm/Frontend/OpenMP/OMP.td
@@ -1414,6 +1414,11 @@ def OMP_Stripe : Directive<[Spelling<"stripe">]> {
let association = AS_LoopNest;
let category = CA_Executable;
}
+def OMP_Split : Directive<[Spelling<"split">]> {
+ // TODO: Add counts clause support (OMPC_Counts)
+ let association = AS_LoopNest;
+ let category = CA_Executable;
+}
def OMP_Unknown : Directive<[Spelling<"unknown">]> {
let isDefault = true;
let association = AS_None;
>From 0a57b91396898f01dffa1aa55da4cc3ac8305d54 Mon Sep 17 00:00:00 2001
From: amtiwari <amtiwari at amd.com>
Date: Wed, 25 Feb 2026 06:51:02 -0500
Subject: [PATCH 2/8] wip
---
clang/include/clang/AST/RecursiveASTVisitor.h | 3 +++
clang/include/clang/AST/StmtOpenMP.h | 14 ++++++--------
clang/lib/AST/StmtOpenMP.cpp | 14 ++++++--------
3 files changed, 15 insertions(+), 16 deletions(-)
diff --git a/clang/include/clang/AST/RecursiveASTVisitor.h b/clang/include/clang/AST/RecursiveASTVisitor.h
index f97b54276cbee..323f570439724 100644
--- a/clang/include/clang/AST/RecursiveASTVisitor.h
+++ b/clang/include/clang/AST/RecursiveASTVisitor.h
@@ -3194,6 +3194,9 @@ DEF_TRAVERSE_STMT(OMPFuseDirective,
DEF_TRAVERSE_STMT(OMPInterchangeDirective,
{ TRY_TO(TraverseOMPExecutableDirective(S)); })
+DEF_TRAVERSE_STMT(OMPSplitDirective,
+ { TRY_TO(TraverseOMPExecutableDirective(S)); })
+
DEF_TRAVERSE_STMT(OMPForDirective,
{ TRY_TO(TraverseOMPExecutableDirective(S)); })
diff --git a/clang/include/clang/AST/StmtOpenMP.h b/clang/include/clang/AST/StmtOpenMP.h
index 626c39a7b778c..c5b83e17acbcd 100644
--- a/clang/include/clang/AST/StmtOpenMP.h
+++ b/clang/include/clang/AST/StmtOpenMP.h
@@ -6088,7 +6088,7 @@ class OMPSplitDirective final
};
explicit OMPSplitDirective(SourceLocation StartLoc, SourceLocation EndLoc,
- unsigned NumLoops)
+ unsigned NumLoops)
: OMPCanonicalLoopNestTransformationDirective(
OMPSplitDirectiveClass, llvm::omp::OMPD_split, StartLoc, EndLoc,
NumLoops) {}
@@ -6112,18 +6112,16 @@ class OMPSplitDirective final
/// \param TransformedStmt The loop nest after splitting, or nullptr in
/// dependent contexts.
/// \param PreInits Helper preinits statements for the loop nest.
- static OMPSplitDirective *Create(const ASTContext &C,
- SourceLocation StartLoc,
- SourceLocation EndLoc,
- Stmt *AssociatedStmt, unsigned NumLoops,
- Stmt *TransformedStmt, Stmt *PreInits);
+ static OMPSplitDirective *Create(const ASTContext &C, SourceLocation StartLoc,
+ SourceLocation EndLoc, Stmt *AssociatedStmt,
+ unsigned NumLoops, Stmt *TransformedStmt,
+ Stmt *PreInits);
/// Build an empty '#pragma omp split' AST node for deserialization.
///
/// \param C Context of the AST.
/// \param NumLoops Number of associated loops to allocate
- static OMPSplitDirective *CreateEmpty(const ASTContext &C,
- unsigned NumLoops);
+ static OMPSplitDirective *CreateEmpty(const ASTContext &C, unsigned NumLoops);
/// Gets/sets the associated loops after the transformation, i.e. after
/// de-sugaring.
diff --git a/clang/lib/AST/StmtOpenMP.cpp b/clang/lib/AST/StmtOpenMP.cpp
index ada4e66b280f8..6c939cf7f9aeb 100644
--- a/clang/lib/AST/StmtOpenMP.cpp
+++ b/clang/lib/AST/StmtOpenMP.cpp
@@ -552,13 +552,11 @@ OMPInterchangeDirective::CreateEmpty(const ASTContext &C, unsigned NumClauses,
SourceLocation(), SourceLocation(), NumLoops);
}
-OMPSplitDirective *OMPSplitDirective::Create(const ASTContext &C,
- SourceLocation StartLoc,
- SourceLocation EndLoc,
- Stmt *AssociatedStmt,
- unsigned NumLoops,
- Stmt *TransformedStmt,
- Stmt *PreInits) {
+OMPSplitDirective *
+OMPSplitDirective::Create(const ASTContext &C, SourceLocation StartLoc,
+ SourceLocation EndLoc, Stmt *AssociatedStmt,
+ unsigned NumLoops, Stmt *TransformedStmt,
+ Stmt *PreInits) {
OMPSplitDirective *Dir = createDirective<OMPSplitDirective>(
C, {}, AssociatedStmt, TransformedStmtOffset + 1, StartLoc, EndLoc,
NumLoops);
@@ -568,7 +566,7 @@ OMPSplitDirective *OMPSplitDirective::Create(const ASTContext &C,
}
OMPSplitDirective *OMPSplitDirective::CreateEmpty(const ASTContext &C,
- unsigned NumLoops) {
+ unsigned NumLoops) {
return createEmptyDirective<OMPSplitDirective>(
C, /*NumClauses=*/0, /*HasAssociatedStmt=*/true,
TransformedStmtOffset + 1, SourceLocation(), SourceLocation(), NumLoops);
>From 02844251d20249820021a9e6fc58e888ebf66d3c Mon Sep 17 00:00:00 2001
From: amtiwari <amtiwari at amd.com>
Date: Fri, 6 Mar 2026 06:29:06 -0500
Subject: [PATCH 3/8] wip
---
clang/lib/AST/StmtPrinter.cpp | 5 +++++
clang/lib/AST/StmtProfile.cpp | 4 ++++
clang/lib/Sema/TreeTransform.h | 11 +++++++++++
clang/lib/Serialization/ASTReaderStmt.cpp | 4 ++++
clang/lib/Serialization/ASTWriterStmt.cpp | 5 +++++
5 files changed, 29 insertions(+)
diff --git a/clang/lib/AST/StmtPrinter.cpp b/clang/lib/AST/StmtPrinter.cpp
index f4ce4a7573aab..143ff0580a205 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::VisitOMPSplitDirective(OMPSplitDirective *Node) {
+ Indent() << "#pragma omp split";
+ PrintOMPExecutableDirective(Node);
+}
+
void StmtPrinter::VisitOMPFuseDirective(OMPFuseDirective *Node) {
Indent() << "#pragma omp fuse";
PrintOMPExecutableDirective(Node);
diff --git a/clang/lib/AST/StmtProfile.cpp b/clang/lib/AST/StmtProfile.cpp
index 623905188b2dd..375b2207d4dd4 100644
--- a/clang/lib/AST/StmtProfile.cpp
+++ b/clang/lib/AST/StmtProfile.cpp
@@ -1051,6 +1051,10 @@ void StmtProfiler::VisitOMPInterchangeDirective(
VisitOMPCanonicalLoopNestTransformationDirective(S);
}
+void StmtProfiler::VisitOMPSplitDirective(const OMPSplitDirective *S) {
+ VisitOMPCanonicalLoopNestTransformationDirective(S);
+}
+
void StmtProfiler::VisitOMPCanonicalLoopSequenceTransformationDirective(
const OMPCanonicalLoopSequenceTransformationDirective *S) {
VisitOMPExecutableDirective(S);
diff --git a/clang/lib/Sema/TreeTransform.h b/clang/lib/Sema/TreeTransform.h
index 1a050bd6a8737..8f67e71382b1d 100644
--- a/clang/lib/Sema/TreeTransform.h
+++ b/clang/lib/Sema/TreeTransform.h
@@ -9761,6 +9761,17 @@ StmtResult TreeTransform<Derived>::TransformOMPInterchangeDirective(
return Res;
}
+template <typename Derived>
+StmtResult
+TreeTransform<Derived>::TransformOMPSplitDirective(OMPSplitDirective *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) {
diff --git a/clang/lib/Serialization/ASTReaderStmt.cpp b/clang/lib/Serialization/ASTReaderStmt.cpp
index a18fccb6518d2..c338e9bfbf22c 100644
--- a/clang/lib/Serialization/ASTReaderStmt.cpp
+++ b/clang/lib/Serialization/ASTReaderStmt.cpp
@@ -2510,6 +2510,10 @@ void ASTStmtReader::VisitOMPInterchangeDirective(OMPInterchangeDirective *D) {
VisitOMPCanonicalLoopNestTransformationDirective(D);
}
+void ASTStmtReader::VisitOMPSplitDirective(OMPSplitDirective *D) {
+ VisitOMPCanonicalLoopNestTransformationDirective(D);
+}
+
void ASTStmtReader::VisitOMPFuseDirective(OMPFuseDirective *D) {
VisitOMPCanonicalLoopSequenceTransformationDirective(D);
}
diff --git a/clang/lib/Serialization/ASTWriterStmt.cpp b/clang/lib/Serialization/ASTWriterStmt.cpp
index 4fcac4d0261ab..f3531d3d91837 100644
--- a/clang/lib/Serialization/ASTWriterStmt.cpp
+++ b/clang/lib/Serialization/ASTWriterStmt.cpp
@@ -2522,6 +2522,11 @@ void ASTStmtWriter::VisitOMPInterchangeDirective(OMPInterchangeDirective *D) {
Code = serialization::STMT_OMP_INTERCHANGE_DIRECTIVE;
}
+void ASTStmtWriter::VisitOMPSplitDirective(OMPSplitDirective *D) {
+ VisitOMPCanonicalLoopNestTransformationDirective(D);
+ Code = serialization::STMT_OMP_SPLIT_DIRECTIVE;
+}
+
void ASTStmtWriter::VisitOMPCanonicalLoopSequenceTransformationDirective(
OMPCanonicalLoopSequenceTransformationDirective *D) {
VisitStmt(D);
>From 991ac94e4d2376e5c509aea207c69a0d36de9ac7 Mon Sep 17 00:00:00 2001
From: amtiwari <amtiwari at amd.com>
Date: Mon, 9 Mar 2026 07:42:22 -0400
Subject: [PATCH 4/8] wip
---
clang/lib/CodeGen/CGStmt.cpp | 3 +++
1 file changed, 3 insertions(+)
diff --git a/clang/lib/CodeGen/CGStmt.cpp b/clang/lib/CodeGen/CGStmt.cpp
index 0658ecc93d88d..f41ea386487f7 100644
--- a/clang/lib/CodeGen/CGStmt.cpp
+++ b/clang/lib/CodeGen/CGStmt.cpp
@@ -228,6 +228,9 @@ void CodeGenFunction::EmitStmt(const Stmt *S, ArrayRef<const Attr *> Attrs) {
case Stmt::OMPReverseDirectiveClass:
EmitOMPReverseDirective(cast<OMPReverseDirective>(*S));
break;
+ case Stmt::OMPSplitDirectiveClass:
+ EmitOMPSplitDirective(cast<OMPSplitDirective>(*S));
+ break;
case Stmt::OMPInterchangeDirectiveClass:
EmitOMPInterchangeDirective(cast<OMPInterchangeDirective>(*S));
break;
>From dcc5f3f7ec2314b81e8618c566c7e6456e2f32ca Mon Sep 17 00:00:00 2001
From: amtiwari <amtiwari at amd.com>
Date: Mon, 9 Mar 2026 08:16:47 -0400
Subject: [PATCH 5/8] wip
---
clang/lib/Sema/SemaExceptionSpec.cpp | 1 +
clang/lib/Serialization/ASTReaderStmt.cpp | 8 ++++++++
clang/lib/StaticAnalyzer/Core/ExprEngine.cpp | 1 +
clang/tools/libclang/CXCursor.cpp | 3 +++
4 files changed, 13 insertions(+)
diff --git a/clang/lib/Sema/SemaExceptionSpec.cpp b/clang/lib/Sema/SemaExceptionSpec.cpp
index 8df01a8a616c3..4fd800e5e25c4 100644
--- a/clang/lib/Sema/SemaExceptionSpec.cpp
+++ b/clang/lib/Sema/SemaExceptionSpec.cpp
@@ -1496,6 +1496,7 @@ CanThrowResult Sema::canThrow(const Stmt *S) {
case Stmt::OMPUnrollDirectiveClass:
case Stmt::OMPReverseDirectiveClass:
case Stmt::OMPInterchangeDirectiveClass:
+ case Stmt::OMPSplitDirectiveClass:
case Stmt::OMPFuseDirectiveClass:
case Stmt::OMPSingleDirectiveClass:
case Stmt::OMPTargetDataDirectiveClass:
diff --git a/clang/lib/Serialization/ASTReaderStmt.cpp b/clang/lib/Serialization/ASTReaderStmt.cpp
index c338e9bfbf22c..be6e7e0ea90bb 100644
--- a/clang/lib/Serialization/ASTReaderStmt.cpp
+++ b/clang/lib/Serialization/ASTReaderStmt.cpp
@@ -3668,6 +3668,14 @@ Stmt *ASTReader::ReadStmtFromStream(ModuleFile &F) {
break;
}
+ case STMT_OMP_SPLIT_DIRECTIVE: {
+ unsigned NumLoops = Record[ASTStmtReader::NumStmtFields];
+ assert(Record[ASTStmtReader::NumStmtFields + 1] == 0 &&
+ "Split directive has no clauses");
+ S = OMPSplitDirective::CreateEmpty(Context, NumLoops);
+ break;
+ }
+
case STMT_OMP_FUSE_DIRECTIVE: {
unsigned NumClauses = Record[ASTStmtReader::NumStmtFields];
S = OMPFuseDirective::CreateEmpty(Context, NumClauses);
diff --git a/clang/lib/StaticAnalyzer/Core/ExprEngine.cpp b/clang/lib/StaticAnalyzer/Core/ExprEngine.cpp
index 76c382eeb6899..6b5f94a7d2ea2 100644
--- a/clang/lib/StaticAnalyzer/Core/ExprEngine.cpp
+++ b/clang/lib/StaticAnalyzer/Core/ExprEngine.cpp
@@ -1822,6 +1822,7 @@ void ExprEngine::Visit(const Stmt *S, ExplodedNode *Pred,
case Stmt::OMPStripeDirectiveClass:
case Stmt::OMPTileDirectiveClass:
case Stmt::OMPInterchangeDirectiveClass:
+ case Stmt::OMPSplitDirectiveClass:
case Stmt::OMPFuseDirectiveClass:
case Stmt::OMPInteropDirectiveClass:
case Stmt::OMPDispatchDirectiveClass:
diff --git a/clang/tools/libclang/CXCursor.cpp b/clang/tools/libclang/CXCursor.cpp
index 17f485e5c78a5..d8247f8161506 100644
--- a/clang/tools/libclang/CXCursor.cpp
+++ b/clang/tools/libclang/CXCursor.cpp
@@ -696,6 +696,9 @@ CXCursor cxcursor::MakeCXCursor(const Stmt *S, const Decl *Parent,
case Stmt::OMPReverseDirectiveClass:
K = CXCursor_OMPReverseDirective;
break;
+ case Stmt::OMPSplitDirectiveClass:
+ K = CXCursor_UnexposedStmt;
+ break;
case Stmt::OMPInterchangeDirectiveClass:
K = CXCursor_OMPInterchangeDirective;
break;
>From b087df1f9ee96d5a91b169018ef7cbc007b473bb Mon Sep 17 00:00:00 2001
From: amtiwari <amtiwari at amd.com>
Date: Mon, 9 Mar 2026 12:13:02 -0400
Subject: [PATCH 6/8] wip
---
clang/lib/CodeGen/CGStmt.cpp | 3 ++-
1 file changed, 2 insertions(+), 1 deletion(-)
diff --git a/clang/lib/CodeGen/CGStmt.cpp b/clang/lib/CodeGen/CGStmt.cpp
index f41ea386487f7..5d906c378f1bf 100644
--- a/clang/lib/CodeGen/CGStmt.cpp
+++ b/clang/lib/CodeGen/CGStmt.cpp
@@ -229,7 +229,8 @@ void CodeGenFunction::EmitStmt(const Stmt *S, ArrayRef<const Attr *> Attrs) {
EmitOMPReverseDirective(cast<OMPReverseDirective>(*S));
break;
case Stmt::OMPSplitDirectiveClass:
- EmitOMPSplitDirective(cast<OMPSplitDirective>(*S));
+ llvm_unreachable(
+ "OMPSplitDirective handled by EmitSimpleOMPExecutableDirective");
break;
case Stmt::OMPInterchangeDirectiveClass:
EmitOMPInterchangeDirective(cast<OMPInterchangeDirective>(*S));
>From 3b9abedcc0fbcda363ca51ba7dd3fe22ecc1c951 Mon Sep 17 00:00:00 2001
From: amtiwari <amtiwari at amd.com>
Date: Fri, 13 Mar 2026 09:48:29 -0400
Subject: [PATCH 7/8] sema
---
clang/include/clang-c/Index.h | 4 +
clang/include/clang/Sema/SemaOpenMP.h | 4 +
clang/lib/Basic/OpenMPKinds.cpp | 3 +-
clang/lib/CodeGen/CGStmt.cpp | 3 +-
clang/lib/CodeGen/CGStmtOpenMP.cpp | 8 +
clang/lib/CodeGen/CodeGenFunction.h | 1 +
clang/lib/Parse/ParseOpenMP.cpp | 4 +
clang/lib/Sema/SemaOpenMP.cpp | 205 ++++++++++++++++++++++++++
clang/test/OpenMP/split_ast_print.cpp | 28 ++++
clang/test/OpenMP/split_simple_test.c | 26 ++++
clang/tools/libclang/CIndex.cpp | 2 +
clang/tools/libclang/CXCursor.cpp | 2 +-
12 files changed, 286 insertions(+), 4 deletions(-)
create mode 100644 clang/test/OpenMP/split_ast_print.cpp
create mode 100644 clang/test/OpenMP/split_simple_test.c
diff --git a/clang/include/clang-c/Index.h b/clang/include/clang-c/Index.h
index 203634c80d82a..e9dd734445a74 100644
--- a/clang/include/clang-c/Index.h
+++ b/clang/include/clang-c/Index.h
@@ -2166,6 +2166,10 @@ enum CXCursorKind {
*/
CXCursor_OMPFuseDirective = 311,
+ /** OpenMP split directive.
+ */
+ CXCursor_OMPSplitDirective = 312,
+
/** OpenACC Compute Construct.
*/
CXCursor_OpenACCComputeConstruct = 320,
diff --git a/clang/include/clang/Sema/SemaOpenMP.h b/clang/include/clang/Sema/SemaOpenMP.h
index 7853f29f98c25..57382557fd13f 100644
--- a/clang/include/clang/Sema/SemaOpenMP.h
+++ b/clang/include/clang/Sema/SemaOpenMP.h
@@ -457,6 +457,10 @@ class SemaOpenMP : public SemaBase {
/// Called on well-formed '#pragma omp reverse'.
StmtResult ActOnOpenMPReverseDirective(Stmt *AStmt, SourceLocation StartLoc,
SourceLocation EndLoc);
+ /// Called on well-formed '#pragma omp split' after parsing of its
+ /// associated statement.
+ StmtResult ActOnOpenMPSplitDirective(Stmt *AStmt, SourceLocation StartLoc,
+ SourceLocation EndLoc);
/// Called on well-formed '#pragma omp interchange' after parsing of its
/// clauses and the associated statement.
StmtResult ActOnOpenMPInterchangeDirective(ArrayRef<OMPClause *> Clauses,
diff --git a/clang/lib/Basic/OpenMPKinds.cpp b/clang/lib/Basic/OpenMPKinds.cpp
index 2c693b1958ee7..ef01943f11ca5 100644
--- a/clang/lib/Basic/OpenMPKinds.cpp
+++ b/clang/lib/Basic/OpenMPKinds.cpp
@@ -815,7 +815,8 @@ bool clang::isOpenMPLoopBoundSharingDirective(OpenMPDirectiveKind Kind) {
bool clang::isOpenMPCanonicalLoopNestTransformationDirective(
OpenMPDirectiveKind DKind) {
return DKind == OMPD_tile || DKind == OMPD_unroll || DKind == OMPD_reverse ||
- DKind == OMPD_interchange || DKind == OMPD_stripe;
+ DKind == OMPD_split || DKind == OMPD_interchange ||
+ DKind == OMPD_stripe;
}
bool clang::isOpenMPCanonicalLoopSequenceTransformationDirective(
diff --git a/clang/lib/CodeGen/CGStmt.cpp b/clang/lib/CodeGen/CGStmt.cpp
index 5d906c378f1bf..f41ea386487f7 100644
--- a/clang/lib/CodeGen/CGStmt.cpp
+++ b/clang/lib/CodeGen/CGStmt.cpp
@@ -229,8 +229,7 @@ void CodeGenFunction::EmitStmt(const Stmt *S, ArrayRef<const Attr *> Attrs) {
EmitOMPReverseDirective(cast<OMPReverseDirective>(*S));
break;
case Stmt::OMPSplitDirectiveClass:
- llvm_unreachable(
- "OMPSplitDirective handled by EmitSimpleOMPExecutableDirective");
+ EmitOMPSplitDirective(cast<OMPSplitDirective>(*S));
break;
case Stmt::OMPInterchangeDirectiveClass:
EmitOMPInterchangeDirective(cast<OMPInterchangeDirective>(*S));
diff --git a/clang/lib/CodeGen/CGStmtOpenMP.cpp b/clang/lib/CodeGen/CGStmtOpenMP.cpp
index ea89db5471089..9b7890347682d 100644
--- a/clang/lib/CodeGen/CGStmtOpenMP.cpp
+++ b/clang/lib/CodeGen/CGStmtOpenMP.cpp
@@ -196,6 +196,8 @@ class OMPLoopScope : public CodeGenFunction::RunCleanupsScope {
PreInits = Unroll->getPreInits();
} else if (const auto *Reverse = dyn_cast<OMPReverseDirective>(&S)) {
PreInits = Reverse->getPreInits();
+ } else if (const auto *Split = dyn_cast<OMPSplitDirective>(&S)) {
+ PreInits = Split->getPreInits();
} else if (const auto *Interchange =
dyn_cast<OMPInterchangeDirective>(&S)) {
PreInits = Interchange->getPreInits();
@@ -2978,6 +2980,12 @@ void CodeGenFunction::EmitOMPReverseDirective(const OMPReverseDirective &S) {
EmitStmt(S.getTransformedStmt());
}
+void CodeGenFunction::EmitOMPSplitDirective(const OMPSplitDirective &S) {
+ // Emit the de-sugared statement (the two split loops).
+ OMPTransformDirectiveScopeRAII SplitScope(*this, &S);
+ EmitStmt(S.getTransformedStmt());
+}
+
void CodeGenFunction::EmitOMPInterchangeDirective(
const OMPInterchangeDirective &S) {
// Emit the de-sugared statement.
diff --git a/clang/lib/CodeGen/CodeGenFunction.h b/clang/lib/CodeGen/CodeGenFunction.h
index ae2956eeac57a..d82a589ae6b7a 100644
--- a/clang/lib/CodeGen/CodeGenFunction.h
+++ b/clang/lib/CodeGen/CodeGenFunction.h
@@ -3907,6 +3907,7 @@ class CodeGenFunction : public CodeGenTypeCache {
void EmitOMPStripeDirective(const OMPStripeDirective &S);
void EmitOMPUnrollDirective(const OMPUnrollDirective &S);
void EmitOMPReverseDirective(const OMPReverseDirective &S);
+ void EmitOMPSplitDirective(const OMPSplitDirective &S);
void EmitOMPInterchangeDirective(const OMPInterchangeDirective &S);
void EmitOMPFuseDirective(const OMPFuseDirective &S);
void EmitOMPForDirective(const OMPForDirective &S);
diff --git a/clang/lib/Parse/ParseOpenMP.cpp b/clang/lib/Parse/ParseOpenMP.cpp
index b41803d23cb25..75301f3985354 100644
--- a/clang/lib/Parse/ParseOpenMP.cpp
+++ b/clang/lib/Parse/ParseOpenMP.cpp
@@ -3414,6 +3414,10 @@ OMPClause *Parser::ParseOpenMPClause(OpenMPDirectiveKind DKind,
}
Clause = ParseOpenMPPermutationClause();
break;
+ case OMPC_counts:
+ // TODO: Implement ParseOpenMPCountsClause() - not yet worked on
+ SkipUntil(tok::r_paren, tok::comma, StopBeforeMatch);
+ break;
case OMPC_uses_allocators:
Clause = ParseOpenMPUsesAllocatorClause(DKind);
break;
diff --git a/clang/lib/Sema/SemaOpenMP.cpp b/clang/lib/Sema/SemaOpenMP.cpp
index e90884a89bf6e..8c22780b7ae4b 100644
--- a/clang/lib/Sema/SemaOpenMP.cpp
+++ b/clang/lib/Sema/SemaOpenMP.cpp
@@ -4591,6 +4591,7 @@ void SemaOpenMP::ActOnOpenMPRegionStart(OpenMPDirectiveKind DKind,
case OMPD_stripe:
case OMPD_unroll:
case OMPD_reverse:
+ case OMPD_split:
case OMPD_interchange:
case OMPD_fuse:
case OMPD_assume:
@@ -6430,6 +6431,13 @@ StmtResult SemaOpenMP::ActOnOpenMPExecutableDirective(
"reverse directive does not support any clauses");
Res = ActOnOpenMPReverseDirective(AStmt, StartLoc, EndLoc);
break;
+ case OMPD_split:
+ // TODO: Add counts clause support - not yet worked on
+ // Currently only supports basic split without clauses.
+ assert(ClausesWithImplicit.empty() &&
+ "split directive does not support any clauses");
+ Res = ActOnOpenMPSplitDirective(AStmt, StartLoc, EndLoc);
+ break;
case OMPD_interchange:
Res = ActOnOpenMPInterchangeDirective(ClausesWithImplicit, AStmt, StartLoc,
EndLoc);
@@ -15817,6 +15825,203 @@ StmtResult SemaOpenMP::ActOnOpenMPReverseDirective(Stmt *AStmt,
buildPreInits(Context, PreInits));
}
+StmtResult SemaOpenMP::ActOnOpenMPSplitDirective(Stmt *AStmt,
+ SourceLocation StartLoc,
+ SourceLocation EndLoc) {
+ ASTContext &Context = getASTContext();
+ Scope *CurScope = SemaRef.getCurScope();
+
+ // Empty statement should only be possible if there already was an error.
+ if (!AStmt)
+ return StmtError();
+
+ constexpr unsigned NumLoops = 1;
+ Stmt *Body = nullptr;
+ SmallVector<OMPLoopBasedDirective::HelperExprs, NumLoops> LoopHelpers(
+ NumLoops);
+ SmallVector<SmallVector<Stmt *>, NumLoops + 1> OriginalInits;
+ if (!checkTransformableLoopNest(OMPD_split, AStmt, NumLoops, LoopHelpers,
+ Body, OriginalInits))
+ return StmtError();
+
+ // Delay applying the transformation to when template is completely
+ // instantiated.
+ if (SemaRef.CurContext->isDependentContext())
+ return OMPSplitDirective::Create(Context, StartLoc, EndLoc, AStmt, NumLoops,
+ nullptr, nullptr);
+
+ assert(LoopHelpers.size() == NumLoops &&
+ "Expecting a single-dimensional loop iteration space");
+ assert(OriginalInits.size() == NumLoops &&
+ "Expecting a single-dimensional loop iteration space");
+ OMPLoopBasedDirective::HelperExprs &LoopHelper = LoopHelpers.front();
+
+ // Find the loop statement.
+ Stmt *LoopStmt = nullptr;
+ collectLoopStmts(AStmt, {LoopStmt});
+
+ // Determine the PreInit declarations.
+ SmallVector<Stmt *> PreInits;
+ addLoopPreInits(Context, LoopHelper, LoopStmt, OriginalInits[0], PreInits);
+
+ auto *IterationVarRef = cast<DeclRefExpr>(LoopHelper.IterationVarRef);
+ QualType IVTy = IterationVarRef->getType();
+ uint64_t IVWidth = Context.getTypeSize(IVTy);
+ auto *OrigVar = cast<DeclRefExpr>(LoopHelper.Counters.front());
+
+ // Iteration variable SourceLocations.
+ SourceLocation OrigVarLoc = OrigVar->getExprLoc();
+ SourceLocation OrigVarLocBegin = OrigVar->getBeginLoc();
+ SourceLocation OrigVarLocEnd = OrigVar->getEndLoc();
+
+ // Locations pointing to the transformation.
+ SourceLocation TransformLoc = StartLoc;
+
+ // Internal variable names.
+ std::string OrigVarName = OrigVar->getNameInfo().getAsString();
+
+ // For Subexpressions with more than one use, we define a lambda
+ // that creates a new AST node at every use.
+ CaptureVars CopyTransformer(SemaRef);
+ auto MakeNumIterations = [&CopyTransformer, &LoopHelper]() -> Expr * {
+ return AssertSuccess(
+ CopyTransformer.TransformExpr(LoopHelper.NumIterations));
+ };
+
+ // For split, we currently divide the loop into two equal parts.
+ // First loop: i = 0; i < n/2; ++i
+ // Second loop: i = n/2; i < n; ++i
+ // TODO: Add counts clause support - not yet worked on
+
+ // Create iteration variable for the first split loop.
+ SmallString<64> FirstIVName(".split.first.iv.");
+ FirstIVName += OrigVarName;
+ VarDecl *FirstIVDecl =
+ buildVarDecl(SemaRef, {}, IVTy, FirstIVName, nullptr, OrigVar);
+ auto MakeFirstRef = [&SemaRef = this->SemaRef, FirstIVDecl, IVTy,
+ OrigVarLoc]() {
+ return buildDeclRefExpr(SemaRef, FirstIVDecl, IVTy, OrigVarLoc);
+ };
+
+ // Create iteration variable for the second split loop.
+ SmallString<64> SecondIVName(".split.second.iv.");
+ SecondIVName += OrigVarName;
+ VarDecl *SecondIVDecl =
+ buildVarDecl(SemaRef, {}, IVTy, SecondIVName, nullptr, OrigVar);
+ auto MakeSecondRef = [&SemaRef = this->SemaRef, SecondIVDecl, IVTy,
+ OrigVarLoc]() {
+ return buildDeclRefExpr(SemaRef, SecondIVDecl, IVTy, OrigVarLoc);
+ };
+
+ // Create n/2 expression for the split point.
+ auto *Two = IntegerLiteral::Create(Context, llvm::APInt(IVWidth, 2), IVTy,
+ TransformLoc);
+ ExprResult HalfIterations = SemaRef.BuildBinOp(CurScope, TransformLoc, BO_Div,
+ MakeNumIterations(), Two);
+ if (!HalfIterations.isUsable())
+ return StmtError();
+
+ // First loop: init-statement: i = 0
+ auto *Zero = IntegerLiteral::Create(Context, llvm::APInt::getZero(IVWidth),
+ FirstIVDecl->getType(), OrigVarLoc);
+ SemaRef.AddInitializerToDecl(FirstIVDecl, Zero, /*DirectInit=*/false);
+ StmtResult FirstInit = new (Context)
+ DeclStmt(DeclGroupRef(FirstIVDecl), OrigVarLocBegin, OrigVarLocEnd);
+ if (!FirstInit.isUsable())
+ return StmtError();
+
+ // First loop: cond-expression (i < n/2)
+ ExprResult FirstCond =
+ SemaRef.BuildBinOp(CurScope, LoopHelper.Cond->getExprLoc(), BO_LT,
+ MakeFirstRef(), HalfIterations.get());
+ if (!FirstCond.isUsable())
+ return StmtError();
+
+ // First loop: incr-statement (++i)
+ ExprResult FirstIncr = SemaRef.BuildUnaryOp(
+ CurScope, LoopHelper.Inc->getExprLoc(), UO_PreInc, MakeFirstRef());
+ if (!FirstIncr.isUsable())
+ return StmtError();
+
+ // First loop: body - update original variable and execute body
+ // We need to create a copy of LoopHelper.Updates that uses FirstIV instead
+ // of the iteration variable. For now, use a simpler approach: directly
+ // assign the first IV to the original variable.
+ SmallVector<Stmt *, 4> FirstBodyStmts;
+ // Create update statement: origVar = .split.first.iv
+ // We'll use a BinaryOperator for assignment
+ ExprResult FirstUpdateExpr = SemaRef.BuildBinOp(
+ CurScope, OrigVarLoc, BO_Assign, OrigVar, MakeFirstRef());
+ if (!FirstUpdateExpr.isUsable())
+ return StmtError();
+ FirstBodyStmts.push_back(FirstUpdateExpr.get());
+ if (auto *CXXRangeFor = dyn_cast<CXXForRangeStmt>(LoopStmt))
+ FirstBodyStmts.push_back(CXXRangeFor->getLoopVarStmt());
+ FirstBodyStmts.push_back(Body);
+ auto *FirstBody =
+ CompoundStmt::Create(Context, FirstBodyStmts, FPOptionsOverride(),
+ Body->getBeginLoc(), Body->getEndLoc());
+
+ // Create first loop
+ auto *FirstLoop = new (Context)
+ ForStmt(Context, FirstInit.get(), FirstCond.get(), nullptr,
+ FirstIncr.get(), FirstBody, LoopHelper.Init->getBeginLoc(),
+ LoopHelper.Init->getBeginLoc(), LoopHelper.Inc->getEndLoc());
+
+ // Second loop: init-statement (i = n/2)
+ SemaRef.AddInitializerToDecl(SecondIVDecl, HalfIterations.get(),
+ /*DirectInit=*/false);
+ StmtResult SecondInit = new (Context)
+ DeclStmt(DeclGroupRef(SecondIVDecl), OrigVarLocBegin, OrigVarLocEnd);
+ if (!SecondInit.isUsable())
+ return StmtError();
+
+ // Second loop: cond-expression (i < n)
+ ExprResult SecondCond =
+ SemaRef.BuildBinOp(CurScope, LoopHelper.Cond->getExprLoc(), BO_LT,
+ MakeSecondRef(), MakeNumIterations());
+ if (!SecondCond.isUsable())
+ return StmtError();
+
+ // Second loop: incr-statement (++i)
+ ExprResult SecondIncr = SemaRef.BuildUnaryOp(
+ CurScope, LoopHelper.Inc->getExprLoc(), UO_PreInc, MakeSecondRef());
+ if (!SecondIncr.isUsable())
+ return StmtError();
+
+ // Second loop: body - update original variable and execute body
+ SmallVector<Stmt *, 4> SecondBodyStmts;
+ // Create update statement: origVar = .split.second.iv
+ ExprResult SecondUpdateExpr = SemaRef.BuildBinOp(
+ CurScope, OrigVarLoc, BO_Assign, OrigVar, MakeSecondRef());
+ if (!SecondUpdateExpr.isUsable())
+ return StmtError();
+ SecondBodyStmts.push_back(SecondUpdateExpr.get());
+ if (auto *CXXRangeFor = dyn_cast<CXXForRangeStmt>(LoopStmt))
+ SecondBodyStmts.push_back(CXXRangeFor->getLoopVarStmt());
+ SecondBodyStmts.push_back(Body);
+ auto *SecondBody =
+ CompoundStmt::Create(Context, SecondBodyStmts, FPOptionsOverride(),
+ Body->getBeginLoc(), Body->getEndLoc());
+
+ // Create second loop
+ auto *SecondLoop = new (Context)
+ ForStmt(Context, SecondInit.get(), SecondCond.get(), nullptr,
+ SecondIncr.get(), SecondBody, LoopHelper.Init->getBeginLoc(),
+ LoopHelper.Init->getBeginLoc(), LoopHelper.Inc->getEndLoc());
+
+ // Combine both loops into a compound statement
+ SmallVector<Stmt *, 2> SplitLoops;
+ SplitLoops.push_back(FirstLoop);
+ SplitLoops.push_back(SecondLoop);
+ auto *SplitStmt =
+ CompoundStmt::Create(Context, SplitLoops, FPOptionsOverride(),
+ FirstLoop->getBeginLoc(), SecondLoop->getEndLoc());
+
+ return OMPSplitDirective::Create(Context, StartLoc, EndLoc, AStmt, NumLoops,
+ SplitStmt, buildPreInits(Context, PreInits));
+}
+
StmtResult SemaOpenMP::ActOnOpenMPInterchangeDirective(
ArrayRef<OMPClause *> Clauses, Stmt *AStmt, SourceLocation StartLoc,
SourceLocation EndLoc) {
diff --git a/clang/test/OpenMP/split_ast_print.cpp b/clang/test/OpenMP/split_ast_print.cpp
new file mode 100644
index 0000000000000..b24eae4a9bead
--- /dev/null
+++ b/clang/test/OpenMP/split_ast_print.cpp
@@ -0,0 +1,28 @@
+// Check no warnings/errors and that split is recognized
+// RUN: %clang_cc1 -triple x86_64-pc-linux-gnu -fopenmp -fopenmp-version=60 -fsyntax-only -verify %s
+// expected-no-diagnostics
+
+// Check AST: OMPSplitDirective with associated for-loop
+// RUN: %clang_cc1 -triple x86_64-pc-linux-gnu -fopenmp -fopenmp-version=60 -ast-dump %s | FileCheck %s --check-prefix=DUMP
+
+// Check unparsing
+// RUN: %clang_cc1 -triple x86_64-pc-linux-gnu -fopenmp -fopenmp-version=60 -ast-print %s | FileCheck %s --check-prefix=PRINT
+
+#ifndef HEADER
+#define HEADER
+
+extern "C" void body(...);
+
+// PRINT-LABEL: void foo(
+// DUMP-LABEL: FunctionDecl {{.*}} foo
+void foo(int n) {
+ // PRINT: #pragma omp split
+ // DUMP: OMPSplitDirective
+ #pragma omp split
+ // PRINT: for (int i = 0; i < n; ++i)
+ // DUMP: ForStmt
+ for (int i = 0; i < n; ++i)
+ body(i);
+}
+
+#endif
diff --git a/clang/test/OpenMP/split_simple_test.c b/clang/test/OpenMP/split_simple_test.c
new file mode 100644
index 0000000000000..bc0d3c4770890
--- /dev/null
+++ b/clang/test/OpenMP/split_simple_test.c
@@ -0,0 +1,26 @@
+/*
+ * Simple test for #pragma omp split: one canonical for-loop is transformed
+ * into two loops (first half and second half of iterations). This file
+ * verifies compilation and correct result at runtime.
+ *
+ * Compile: clang -fopenmp -fopenmp-version=60 -o split_simple_test split_simple_test.c
+ * Run: ./split_simple_test
+ * Expected: prints "sum 0..9 = 45 (expected 45)", exit code 0.
+ */
+// Verify the split directive compiles and links.
+// RUN: %clang -fopenmp -fopenmp-version=60 -o %t %s
+
+#include <stdio.h>
+
+int main(void) {
+ const int n = 10;
+ int sum = 0;
+
+#pragma omp split
+ for (int i = 0; i < n; ++i) {
+ sum += i;
+ }
+
+ printf("sum 0..%d = %d (expected %d)\n", n - 1, sum, n * (n - 1) / 2);
+ return (sum == n * (n - 1) / 2) ? 0 : 1;
+}
diff --git a/clang/tools/libclang/CIndex.cpp b/clang/tools/libclang/CIndex.cpp
index 31b6a3222d916..74600ea55e45c 100644
--- a/clang/tools/libclang/CIndex.cpp
+++ b/clang/tools/libclang/CIndex.cpp
@@ -6326,6 +6326,8 @@ CXString clang_getCursorKindSpelling(enum CXCursorKind Kind) {
return cxstring::createRef("OMPInterchangeDirective");
case CXCursor_OMPFuseDirective:
return cxstring::createRef("OMPFuseDirective");
+ case CXCursor_OMPSplitDirective:
+ return cxstring::createRef("OMPSplitDirective");
case CXCursor_OMPForDirective:
return cxstring::createRef("OMPForDirective");
case CXCursor_OMPForSimdDirective:
diff --git a/clang/tools/libclang/CXCursor.cpp b/clang/tools/libclang/CXCursor.cpp
index d8247f8161506..4a3afa8b64675 100644
--- a/clang/tools/libclang/CXCursor.cpp
+++ b/clang/tools/libclang/CXCursor.cpp
@@ -697,7 +697,7 @@ CXCursor cxcursor::MakeCXCursor(const Stmt *S, const Decl *Parent,
K = CXCursor_OMPReverseDirective;
break;
case Stmt::OMPSplitDirectiveClass:
- K = CXCursor_UnexposedStmt;
+ K = CXCursor_OMPSplitDirective;
break;
case Stmt::OMPInterchangeDirectiveClass:
K = CXCursor_OMPInterchangeDirective;
>From cd1d79b3f0505fc401528586ab888251c545d908 Mon Sep 17 00:00:00 2001
From: amtiwari <amtiwari at amd.com>
Date: Fri, 13 Mar 2026 10:21:40 -0400
Subject: [PATCH 8/8] duplicate_split_def_removed
---
llvm/include/llvm/Frontend/OpenMP/OMP.td | 10 ----------
1 file changed, 10 deletions(-)
diff --git a/llvm/include/llvm/Frontend/OpenMP/OMP.td b/llvm/include/llvm/Frontend/OpenMP/OMP.td
index fc3da2837b208..0703428186e7c 100644
--- a/llvm/include/llvm/Frontend/OpenMP/OMP.td
+++ b/llvm/include/llvm/Frontend/OpenMP/OMP.td
@@ -1202,16 +1202,6 @@ def OMP_EndSingle : Directive<[Spelling<"end single">]> {
let category = OMP_Single.category;
let languages = [L_Fortran];
}
-def OMP_Split : Directive<[Spelling<"split">]> {
- let allowedClauses = [
- VersionedClause<OMPC_Apply, 60>,
- ];
- let allowedOnceClauses = [
- VersionedClause<OMPC_Counts, 60>,
- ];
- let association = AS_LoopNest;
- let category = CA_Executable;
-}
def OMP_Target : Directive<[Spelling<"target">]> {
let allowedClauses = [
VersionedClause<OMPC_Allocate>,
More information about the cfe-commits
mailing list