https://github.com/zahiraam updated 
https://github.com/llvm/llvm-project/pull/231852

>From d00e1b99db66d6281c96151703a329b19fd2df52 Mon Sep 17 00:00:00 2001
From: Zahira Ammarguellat <[email protected]>
Date: Wed, 14 Oct 2026 03:28:50 -0700
Subject: [PATCH 1/3] [OpenMP] Allow loop-transforming constructs in simd
 regions for OpenMP 6.0

---
 clang/docs/ReleaseNotes.md                    |  3 +
 .../clang/Basic/DiagnosticSemaKinds.td        |  3 +-
 clang/include/clang/Basic/OpenMPKinds.h       |  9 ++
 clang/lib/Basic/OpenMPKinds.cpp               | 15 ++++
 clang/lib/Sema/SemaOpenMP.cpp                 | 13 ++-
 .../simd_loop_transformation_codegen.cpp      | 28 ++++++
 .../simd_loop_transformation_messages.cpp     | 89 +++++++++++++++++++
 7 files changed, 155 insertions(+), 5 deletions(-)
 create mode 100644 clang/test/OpenMP/simd_loop_transformation_codegen.cpp
 create mode 100644 clang/test/OpenMP/simd_loop_transformation_messages.cpp

diff --git a/clang/docs/ReleaseNotes.md b/clang/docs/ReleaseNotes.md
index 231587a3508d1..1d62b6c63d975 100644
--- a/clang/docs/ReleaseNotes.md
+++ b/clang/docs/ReleaseNotes.md
@@ -1260,6 +1260,9 @@ The `alpha.cplusplus.UseAfterLifetimeEnd` checker was 
renamed to `alpha.core.Use
   the clause was parsed but its condition was discarded without effect.
 - Fixed a crash when the loop variable or a loop bound of an OpenMP loop has a
   `_BitInt` type wider than any standard integer type. (#GH140074)
+- Loop-transforming constructs such as `tile` and `unroll` are now allowed
+  inside a `simd` region for OpenMP 6.0 or later, which classifies them as
+  simdizable.
 
 - Added support for capturing structured bindings in OpenMP regions
   (a C++20 extension; warned as an extension in C++17). Individual bindings
diff --git a/clang/include/clang/Basic/DiagnosticSemaKinds.td 
b/clang/include/clang/Basic/DiagnosticSemaKinds.td
index cc87f556d50dc..c436b57f9ceb6 100644
--- a/clang/include/clang/Basic/DiagnosticSemaKinds.td
+++ b/clang/include/clang/Basic/DiagnosticSemaKinds.td
@@ -12368,7 +12368,8 @@ def err_omp_prohibited_region : Error<
   "; perhaps you forget to enclose 'omp %3' directive into a teams region?|"
   "; perhaps you forget to enclose 'omp %3' directive into a for, simd, for 
simd, parallel for, or parallel for simd region?}2">;
 def err_omp_prohibited_region_simd : Error<
-  "OpenMP constructs may not be nested inside a simd region%select{| except 
for ordered simd, simd, scan, or atomic directive}0">;
+  "OpenMP constructs may not be nested inside a simd region%select{| except 
for ordered simd, simd, scan, or atomic directive"
+  "| except for ordered simd, simd, scan, atomic, or loop-transforming 
directive}0">;
 def err_omp_prohibited_region_atomic : Error<
   "OpenMP constructs may not be nested inside an atomic region">;
 def err_omp_prohibited_region_order
diff --git a/clang/include/clang/Basic/OpenMPKinds.h 
b/clang/include/clang/Basic/OpenMPKinds.h
index 36c388668a455..4515efdf663ec 100644
--- a/clang/include/clang/Basic/OpenMPKinds.h
+++ b/clang/include/clang/Basic/OpenMPKinds.h
@@ -516,6 +516,15 @@ bool isOpenMPCapturingDirective(OpenMPDirectiveKind DKind);
 /// otherwise - false.
 bool isOpenMPOrderConcurrentNestableDirective(OpenMPDirectiveKind DKind,
                                               const LangOptions &LangOpts);
+
+/// Checks if the specified directive is a simdizable directive, i.e. a
+/// directive that may be encountered during execution of a simd region.
+/// \param DKind Specified directive.
+/// \param LangOpts Used for getting the OpenMP version.
+/// \return true - if the above condition is met for this directive
+/// otherwise - false.
+bool isOpenMPSimdizableDirective(OpenMPDirectiveKind DKind,
+                                 const LangOptions &LangOpts);
 }
 
 template <>
diff --git a/clang/lib/Basic/OpenMPKinds.cpp b/clang/lib/Basic/OpenMPKinds.cpp
index 99a2a4db4ab53..ca06fe6225328 100644
--- a/clang/lib/Basic/OpenMPKinds.cpp
+++ b/clang/lib/Basic/OpenMPKinds.cpp
@@ -946,6 +946,21 @@ bool clang::isOpenMPOrderConcurrentNestableDirective(
   return false;
 }
 
+bool clang::isOpenMPSimdizableDirective(OpenMPDirectiveKind DKind,
+                                        const LangOptions &LangOpts) {
+  // Directives that may be encountered during execution of a simd region are:
+  // OpenMP 5.x: ordered simd, simd, scan and atomic
+  // OpenMP 6.0: above plus all loop-transformation directives
+  if (DKind == OMPD_ordered_blockassoc || DKind == OMPD_simd ||
+      DKind == OMPD_scan || DKind == OMPD_atomic)
+    return true;
+
+  if (LangOpts.OpenMP >= 60)
+    return isOpenMPLoopTransformationDirective(DKind);
+
+  return false;
+}
+
 void clang::getOpenMPCaptureRegions(
     SmallVectorImpl<OpenMPDirectiveKind> &CaptureRegions,
     OpenMPDirectiveKind DKind) {
diff --git a/clang/lib/Sema/SemaOpenMP.cpp b/clang/lib/Sema/SemaOpenMP.cpp
index a3be416d2da24..ad7eb8dcbebbb 100644
--- a/clang/lib/Sema/SemaOpenMP.cpp
+++ b/clang/lib/Sema/SemaOpenMP.cpp
@@ -5395,9 +5395,8 @@ static bool checkNestingOfRegions(Sema &SemaRef, const 
DSAStackTy *Stack,
   }
   if (isOpenMPSimdDirective(ParentRegion) &&
       ((OMPVersion <= 45 && CurrentRegion != OMPD_ordered_blockassoc) ||
-       (OMPVersion >= 50 && CurrentRegion != OMPD_ordered_blockassoc &&
-        CurrentRegion != OMPD_simd && CurrentRegion != OMPD_atomic &&
-        CurrentRegion != OMPD_scan))) {
+       (OMPVersion >= 50 &&
+        !isOpenMPSimdizableDirective(CurrentRegion, SemaRef.LangOpts)))) {
     // OpenMP [2.16, Nesting of Regions]
     // OpenMP constructs may not be nested inside a simd region.
     // OpenMP [2.8.1,simd Construct, Restrictions]
@@ -5410,10 +5409,16 @@ static bool checkNestingOfRegions(Sema &SemaRef, const 
DSAStackTy *Stack,
     // The only OpenMP constructs that can be encountered during execution of
     // a simd region are the atomic construct, the loop construct, the simd
     // construct and the ordered construct with the simd clause.
+    // OpenMP 5.2 [10.4, simd Construct, Restrictions]
+    // Only simdizable constructs can be encountered during execution of a
+    // simd region.
+    // OpenMP 6.0 makes all loop-transforming constructs simdizable.
     SemaRef.Diag(StartLoc, (CurrentRegion != OMPD_simd)
                                ? diag::err_omp_prohibited_region_simd
                                : diag::warn_omp_nesting_simd)
-        << (OMPVersion >= 50 ? 1 : 0);
+        << (OMPVersion >= 60   ? 2
+            : OMPVersion >= 50 ? 1
+                               : 0);
     return CurrentRegion != OMPD_simd;
   }
   if (EnclosingConstruct == OMPD_atomic) {
diff --git a/clang/test/OpenMP/simd_loop_transformation_codegen.cpp 
b/clang/test/OpenMP/simd_loop_transformation_codegen.cpp
new file mode 100644
index 0000000000000..09f5747189c7e
--- /dev/null
+++ b/clang/test/OpenMP/simd_loop_transformation_codegen.cpp
@@ -0,0 +1,28 @@
+// RUN: %clang_cc1 -triple x86_64-unknown-linux-gnu -fopenmp \
+// RUN:   -fopenmp-version=60 -emit-llvm -o - %s | FileCheck %s
+
+// OpenMP 6.0 allows loop-transforming constructs inside a simd region. Check
+// that the loops generated by the inner tile construct are emitted inside the
+// simd loop and that their accesses belong to the simd loop's access group.
+
+void use(int);
+
+// CHECK-LABEL: define {{.*}}void @_Z12tile_in_simdi(
+// CHECK: store i32 0, ptr %.floor_0.iv.i{{.*}}!llvm.access.group 
[[AG:![0-9]+]]
+// CHECK: store i32 {{.*}}, ptr %.tile_0.iv.i{{.*}}!llvm.access.group [[AG]]
+// CHECK: call void @_Z3usei(i32 noundef {{.*}}), !llvm.access.group [[AG]]
+// CHECK: br label %omp.inner.for.cond, !llvm.loop [[SIMD_LOOP:![0-9]+]]
+void tile_in_simd(int n) {
+#pragma omp simd
+  for (int j = 0; j < n; ++j) {
+#pragma omp tile sizes(4)
+    for (int i = 0; i < n; ++i)
+      use(i);
+  }
+}
+
+// CHECK: [[AG]] = distinct !{}
+// CHECK: [[SIMD_LOOP]] = distinct !{[[SIMD_LOOP]], [[PA:![0-9]+]],
+// CHECK-SAME: [[VE:![0-9]+]]}
+// CHECK: [[PA]] = !{!"llvm.loop.parallel_accesses", [[AG]]}
+// CHECK: [[VE]] = !{!"llvm.loop.vectorize.enable"}
diff --git a/clang/test/OpenMP/simd_loop_transformation_messages.cpp 
b/clang/test/OpenMP/simd_loop_transformation_messages.cpp
new file mode 100644
index 0000000000000..ebff3da6bf592
--- /dev/null
+++ b/clang/test/OpenMP/simd_loop_transformation_messages.cpp
@@ -0,0 +1,89 @@
+// RUN: %clang_cc1 -fsyntax-only -fopenmp -fopenmp-version=51 \
+// RUN:   -triple x86_64-unknown-unknown -verify=expected,omp5x %s
+// RUN: %clang_cc1 -fsyntax-only -fopenmp -fopenmp-version=52 \
+// RUN:   -triple x86_64-unknown-unknown -verify=expected,omp5x %s
+// RUN: %clang_cc1 -fsyntax-only -fopenmp -fopenmp-version=60 \
+// RUN:   -triple x86_64-unknown-unknown -verify=expected,omp60 %s
+
+// RUN: %clang_cc1 -fsyntax-only -fopenmp-simd -fopenmp-version=51 \
+// RUN:   -triple x86_64-unknown-unknown -verify=expected,omp5x %s
+// RUN: %clang_cc1 -fsyntax-only -fopenmp-simd -fopenmp-version=52 \
+// RUN:   -triple x86_64-unknown-unknown -verify=expected,omp5x %s
+// RUN: %clang_cc1 -fsyntax-only -fopenmp-simd -fopenmp-version=60 \
+// RUN:   -triple x86_64-unknown-unknown -verify=expected,omp60 %s
+
+// OpenMP 6.0 allows simdizable constructs, which include all loop-transforming
+// constructs, to be encountered during execution of a simd region. Earlier
+// versions do not.
+
+void use(int);
+
+void tile_in_simd(int n) {
+#pragma omp simd
+  for (int j = 0; j < n; ++j) {
+    // omp5x-error@+1 {{scan, or atomic directive}}
+#pragma omp tile sizes(4)
+    for (int i = 0; i < n; ++i)
+      use(i);
+  }
+}
+
+void unroll_in_simd(int n) {
+#pragma omp simd
+  for (int j = 0; j < n; ++j) {
+    // omp5x-error@+1 {{scan, or atomic directive}}
+#pragma omp unroll partial(2)
+    for (int i = 0; i < n; ++i)
+      use(i);
+  }
+}
+
+void tile_in_for_simd(int n) {
+#pragma omp for simd
+  for (int j = 0; j < n; ++j) {
+    // omp5x-error@+1 {{scan, or atomic directive}}
+#pragma omp tile sizes(4)
+    for (int i = 0; i < n; ++i)
+      use(i);
+  }
+}
+
+// Constructs that are not simdizable are still rejected in OpenMP 6.0.
+void parallel_in_simd(int n) {
+#pragma omp simd
+  for (int j = 0; j < n; ++j) {
+    // omp5x-error@+2 {{scan, or atomic directive}}
+    // omp60-error@+1 {{atomic, or loop-transforming directive}}
+#pragma omp parallel
+    use(j);
+  }
+}
+
+#if _OPENMP >= 202411
+// Loop-transforming constructs introduced in OpenMP 6.0.
+void omp60_transformations_in_simd(int n) {
+#pragma omp simd
+  for (int j = 0; j < n; ++j) {
+#pragma omp reverse
+    for (int i = 0; i < n; ++i)
+      use(i);
+#pragma omp interchange
+    for (int i = 0; i < n; ++i)
+      for (int k = 0; k < n; ++k)
+        use(i + k);
+#pragma omp stripe sizes(4)
+    for (int i = 0; i < n; ++i)
+      use(i);
+#pragma omp fuse
+    {
+      for (int i = 0; i < n; ++i)
+        use(i);
+      for (int k = 0; k < n; ++k)
+        use(k);
+    }
+#pragma omp split counts(2, omp_fill)
+    for (int i = 0; i < n; ++i)
+      use(i);
+  }
+}
+#endif

>From 8fdfe1bac6babcbad40c536ac43d99998319232c Mon Sep 17 00:00:00 2001
From: Zahira Ammarguellat <[email protected]>
Date: Mon, 19 Oct 2026 01:56:57 -0700
Subject: [PATCH 2/3] Fixed tests and added them

---
 clang/docs/ReleaseNotes.md                    |   8 +
 .../clang/Basic/DiagnosticSemaKinds.td        |   4 +-
 clang/lib/Sema/SemaOpenMP.cpp                 |  42 ++++-
 .../test/OpenMP/Inputs/nesting_of_regions.cpp |   2 +-
 clang/test/OpenMP/loop_bind_messages.cpp      |  28 ++++
 .../loop_transformation_nesting_messages.cpp  | 144 ++++++++++++++++++
 clang/test/OpenMP/ordered_messages.cpp        |   1 +
 .../simd_loop_transformation_messages.cpp     |  89 -----------
 clang/test/OpenMP/tile_collapse_messages.cpp  |   2 +-
 9 files changed, 219 insertions(+), 101 deletions(-)
 create mode 100644 clang/test/OpenMP/loop_transformation_nesting_messages.cpp
 delete mode 100644 clang/test/OpenMP/simd_loop_transformation_messages.cpp

diff --git a/clang/docs/ReleaseNotes.md b/clang/docs/ReleaseNotes.md
index 1d62b6c63d975..7829b10b32b82 100644
--- a/clang/docs/ReleaseNotes.md
+++ b/clang/docs/ReleaseNotes.md
@@ -1263,6 +1263,14 @@ The `alpha.cplusplus.UseAfterLifetimeEnd` checker was 
renamed to `alpha.core.Use
 - Loop-transforming constructs such as `tile` and `unroll` are now allowed
   inside a `simd` region for OpenMP 6.0 or later, which classifies them as
   simdizable.
+- The `loop` construct without a `bind` clause or with `bind(thread)` is now
+  allowed inside a `simd` region for OpenMP 5.0 or later, as the OpenMP
+  specification permits.
+- Constructs nested inside a loop-transforming construct are now checked
+  against the restrictions of an enclosing `simd` region or of a loop with an
+  `order(concurrent)` clause. Previously, such constructs (e.g. `parallel`
+  inside `tile` inside `simd`, or `critical` inside `tile` inside a loop with
+  `order(concurrent)`) were incorrectly accepted.
 
 - Added support for capturing structured bindings in OpenMP regions
   (a C++20 extension; warned as an extension in C++17). Individual bindings
diff --git a/clang/include/clang/Basic/DiagnosticSemaKinds.td 
b/clang/include/clang/Basic/DiagnosticSemaKinds.td
index c436b57f9ceb6..baecf34999e93 100644
--- a/clang/include/clang/Basic/DiagnosticSemaKinds.td
+++ b/clang/include/clang/Basic/DiagnosticSemaKinds.td
@@ -12368,8 +12368,8 @@ def err_omp_prohibited_region : Error<
   "; perhaps you forget to enclose 'omp %3' directive into a teams region?|"
   "; perhaps you forget to enclose 'omp %3' directive into a for, simd, for 
simd, parallel for, or parallel for simd region?}2">;
 def err_omp_prohibited_region_simd : Error<
-  "OpenMP constructs may not be nested inside a simd region%select{| except 
for ordered simd, simd, scan, or atomic directive"
-  "| except for ordered simd, simd, scan, atomic, or loop-transforming 
directive}0">;
+  "OpenMP constructs may not be nested inside a simd region%select{| except 
for ordered simd, simd, scan, atomic, or loop directive"
+  "| except for ordered simd, simd, scan, atomic, loop, or loop-transforming 
directive}0">;
 def err_omp_prohibited_region_atomic : Error<
   "OpenMP constructs may not be nested inside an atomic region">;
 def err_omp_prohibited_region_order
diff --git a/clang/lib/Sema/SemaOpenMP.cpp b/clang/lib/Sema/SemaOpenMP.cpp
index ad7eb8dcbebbb..3b1966a50baed 100644
--- a/clang/lib/Sema/SemaOpenMP.cpp
+++ b/clang/lib/Sema/SemaOpenMP.cpp
@@ -927,11 +927,31 @@ class DSAStackTy {
   void setRegionHasOrderConcurrent(bool HasOrderConcurrent) {
     getTopOfStack().RegionHasOrderConcurrent = HasOrderConcurrent;
   }
-  /// Returns true, if parent region is order (has associated
-  /// 'order' clause), false - otherwise.
-  bool isParentOrderConcurrent() const {
-    if (const SharingMapTy *Parent = getSecondOnStackOrNull())
-      return Parent->RegionHasOrderConcurrent;
+  /// Returns true if the nearest enclosing directive that is not a
+  /// loop-transforming construct has an order(concurrent) clause.
+  bool isEnclosingOrderConcurrent() const {
+    for (const_iterator I = begin() + std::min<size_t>(1, getStackSize()),
+                        E = end();
+         I != E; ++I) {
+      if (I->RegionHasOrderConcurrent)
+        return true;
+      if (!isOpenMPLoopTransformationDirective(I->Directive))
+        return false;
+    }
+    return false;
+  }
+  /// Returns true if the nearest enclosing directive that is not a
+  /// loop-transforming or ordered simd construct is a simd directive.
+  bool isInSimdRegion() const {
+    for (const_iterator I = begin() + std::min<size_t>(1, getStackSize()),
+                        E = end();
+         I != E; ++I) {
+      if (isOpenMPSimdDirective(I->Directive))
+        return true;
+      if (!isOpenMPLoopTransformationDirective(I->Directive) &&
+          I->Directive != OMPD_ordered_blockassoc)
+        return false;
+    }
     return false;
   }
   /// Marks current region as nowait (it has a 'nowait' clause).
@@ -5386,17 +5406,23 @@ static bool checkNestingOfRegions(Sema &SemaRef, const 
DSAStackTy *Stack,
   OpenMPDirectiveKind EnclosingConstruct = ParentLOC.back();
   llvm::omp::Version OMPVersion = SemaRef.getLangOpts().getOpenMPVersion();
 
-  if (OMPVersion >= 50 && Stack->isParentOrderConcurrent() &&
+  if (OMPVersion >= 50 && Stack->isEnclosingOrderConcurrent() &&
       !isOpenMPOrderConcurrentNestableDirective(CurrentRegion,
                                                 SemaRef.LangOpts)) {
     SemaRef.Diag(StartLoc, diag::err_omp_prohibited_region_order)
         << getOpenMPDirectiveName(CurrentRegion, OMPVersion);
     return true;
   }
-  if (isOpenMPSimdDirective(ParentRegion) &&
+  // A construct nested in a loop-transforming or ordered construct is still
+  // encountered during execution of an enclosing simd region.
+  if (Stack->isInSimdRegion() &&
       ((OMPVersion <= 45 && CurrentRegion != OMPD_ordered_blockassoc) ||
        (OMPVersion >= 50 &&
-        !isOpenMPSimdizableDirective(CurrentRegion, SemaRef.LangOpts)))) {
+        !isOpenMPSimdizableDirective(CurrentRegion, SemaRef.LangOpts) &&
+        // The loop construct is simdizable if and only if its binding region
+        // is not defined: no bind clause, or bind(thread).
+        !(CurrentRegion == OMPD_loop &&
+          (BindKind == OMPC_BIND_unknown || BindKind == OMPC_BIND_thread))))) {
     // OpenMP [2.16, Nesting of Regions]
     // OpenMP constructs may not be nested inside a simd region.
     // OpenMP [2.8.1,simd Construct, Restrictions]
diff --git a/clang/test/OpenMP/Inputs/nesting_of_regions.cpp 
b/clang/test/OpenMP/Inputs/nesting_of_regions.cpp
index 985cdc0e19adc..6fff7a9e6025b 100644
--- a/clang/test/OpenMP/Inputs/nesting_of_regions.cpp
+++ b/clang/test/OpenMP/Inputs/nesting_of_regions.cpp
@@ -231,7 +231,7 @@ void foo() {
 // SIMD DIRECTIVE
 #pragma omp simd
   for (int i = 0; i < 10; ++i) {
-#pragma omp for // omp45-error {{OpenMP constructs may not be nested inside a 
simd region}} omp50-error {{OpenMP constructs may not be nested inside a simd 
region except for ordered simd, simd, scan, or atomic directive}} omp51-error 
{{OpenMP constructs may not be nested inside a simd region except for ordered 
simd, simd, scan, or atomic directive}}
+#pragma omp for // omp45-error {{OpenMP constructs may not be nested inside a 
simd region}} omp50-error {{OpenMP constructs may not be nested inside a simd 
region except for ordered simd, simd, scan, atomic, or loop directive}} 
omp51-error {{OpenMP constructs may not be nested inside a simd region except 
for ordered simd, simd, scan, atomic, or loop directive}}
     for (int i = 0; i < 10; ++i)
       ;
   }
diff --git a/clang/test/OpenMP/loop_bind_messages.cpp 
b/clang/test/OpenMP/loop_bind_messages.cpp
index becd1f40c0c04..bd8f2c6a0e5b9 100644
--- a/clang/test/OpenMP/loop_bind_messages.cpp
+++ b/clang/test/OpenMP/loop_bind_messages.cpp
@@ -1,6 +1,7 @@
 #ifndef HEADER
 #define HEADER
 // RUN: %clang_cc1 -fopenmp -fopenmp-version=50 -verify %s
+// RUN: %clang_cc1 -fopenmp -fopenmp-version=60 -verify %s
 
 #define NNN 50
 int aaa[NNN];
@@ -220,12 +221,39 @@ void orphan_loops() {
   }
 }
 
+// A loop construct is simdizable if and only if its binding region is not
+// defined, i.e. it has no bind clause or bind(thread).
+void loop_in_simd() {
+  #pragma omp simd
+  for (int j = 0; j < NNN; j++) {
+    #pragma omp loop
+    for (int i = 0; i < NNN; i++)
+      aaa[i] = i;
+  }
+
+  #pragma omp simd
+  for (int j = 0; j < NNN; j++) {
+    #pragma omp loop bind(thread)
+    for (int i = 0; i < NNN; i++)
+      aaa[i] = i;
+  }
+
+  #pragma omp simd
+  for (int j = 0; j < NNN; j++) {
+    // expected-error@+1 {{may not be nested inside a simd region}}
+    #pragma omp loop bind(parallel)
+    for (int i = 0; i < NNN; i++)
+      aaa[i] = i;
+  }
+}
+
 int main(int argc, char *argv[]) {
   parallel_loop();
   teams_loop();
   thread_loop();
   parallel_for_with_loop_teams_bind();
   orphan_loops();
+  loop_in_simd();
 }
 
 #endif
diff --git a/clang/test/OpenMP/loop_transformation_nesting_messages.cpp 
b/clang/test/OpenMP/loop_transformation_nesting_messages.cpp
new file mode 100644
index 0000000000000..dc3b57dba0010
--- /dev/null
+++ b/clang/test/OpenMP/loop_transformation_nesting_messages.cpp
@@ -0,0 +1,144 @@
+// RUN: %clang_cc1 -fsyntax-only -fopenmp -fopenmp-version=51 \
+// RUN:   -triple x86_64-unknown-unknown -verify=expected,omp5x %s
+// RUN: %clang_cc1 -fsyntax-only -fopenmp -fopenmp-version=52 \
+// RUN:   -triple x86_64-unknown-unknown -verify=expected,omp5x %s
+// RUN: %clang_cc1 -fsyntax-only -fopenmp -fopenmp-version=60 \
+// RUN:   -triple x86_64-unknown-unknown -verify=expected,omp60 %s
+
+// RUN: %clang_cc1 -fsyntax-only -fopenmp-simd -fopenmp-version=51 \
+// RUN:   -triple x86_64-unknown-unknown -verify=expected,omp5x %s
+// RUN: %clang_cc1 -fsyntax-only -fopenmp-simd -fopenmp-version=52 \
+// RUN:   -triple x86_64-unknown-unknown -verify=expected,omp5x %s
+// RUN: %clang_cc1 -fsyntax-only -fopenmp-simd -fopenmp-version=60 \
+// RUN:   -triple x86_64-unknown-unknown -verify=expected,omp60 %s
+
+// A loop-transforming construct creates no region of its own, so a construct
+// nested in one is still subject to the restrictions of an enclosing simd
+// region or of a loop with an order(concurrent) clause. OpenMP 6.0 allows
+// loop-transforming constructs in both; earlier versions do not.
+
+void use(int);
+
+void tile_in_simd(int n) {
+#pragma omp simd
+  for (int j = 0; j < n; ++j) {
+    // omp5x-error@+1 {{atomic, or loop directive}}
+#pragma omp tile sizes(4)
+    for (int i = 0; i < n; ++i)
+      use(i);
+  }
+}
+
+void unroll_in_simd(int n) {
+#pragma omp simd
+  for (int j = 0; j < n; ++j) {
+    // omp5x-error@+1 {{atomic, or loop directive}}
+#pragma omp unroll partial(2)
+    for (int i = 0; i < n; ++i)
+      use(i);
+  }
+}
+
+void tile_in_for_simd(int n) {
+#pragma omp for simd
+  for (int j = 0; j < n; ++j) {
+    // omp5x-error@+1 {{atomic, or loop directive}}
+#pragma omp tile sizes(4)
+    for (int i = 0; i < n; ++i)
+      use(i);
+  }
+}
+
+// Constructs that are not simdizable are still rejected in OpenMP 6.0.
+void parallel_in_simd(int n) {
+#pragma omp simd
+  for (int j = 0; j < n; ++j) {
+    // omp5x-error@+2 {{atomic, or loop directive}}
+    // omp60-error@+1 {{loop, or loop-transforming directive}}
+#pragma omp parallel
+    use(j);
+  }
+}
+
+// A loop-transforming construct creates no region, so a construct nested in
+// one is still inside the enclosing simd region.
+void parallel_in_tile_in_simd(int n) {
+#pragma omp simd
+  for (int j = 0; j < n; ++j) {
+    // omp5x-error@+1 {{atomic, or loop directive}}
+#pragma omp tile sizes(4)
+    for (int i = 0; i < n; ++i) {
+      // omp5x-error@+2 {{atomic, or loop directive}}
+      // omp60-error@+1 {{loop, or loop-transforming directive}}
+#pragma omp parallel
+      use(i);
+    }
+  }
+}
+
+// The body of an ordered simd construct is also inside the simd region.
+void parallel_in_ordered_simd(int n) {
+#pragma omp simd
+  for (int j = 0; j < n; ++j) {
+#pragma omp ordered simd
+    {
+      // omp5x-error@+2 {{atomic, or loop directive}}
+      // omp60-error@+1 {{loop, or loop-transforming directive}}
+#pragma omp parallel
+      use(j);
+    }
+  }
+}
+
+// A loop-transforming construct associated with the simd construct itself.
+void simd_applied_to_tile(int n) {
+#pragma omp simd
+// omp5x-error@+1 {{atomic, or loop directive}}
+#pragma omp tile sizes(4)
+  for (int i = 0; i < n; ++i)
+    use(i);
+}
+
+// A construct nested in a loop-transforming construct is still in the region
+// associated with an order(concurrent) clause.
+void critical_in_tile_in_order_concurrent(int n) {
+#pragma omp parallel for order(concurrent)
+  for (int j = 0; j < n; ++j) {
+    // omp5x-error@+1 {{construct 'tile' not allowed in a region}}
+#pragma omp tile sizes(2)
+    for (int i = 0; i < n; ++i) {
+      // expected-error@+1 {{construct 'critical' not allowed in a region}}
+#pragma omp critical
+      use(i);
+    }
+  }
+}
+
+#if _OPENMP >= 202411
+// Loop-transforming constructs introduced in OpenMP 6.0.
+void omp60_transformations_in_simd(int n) {
+#pragma omp simd
+  for (int j = 0; j < n; ++j) {
+#pragma omp reverse
+    for (int i = 0; i < n; ++i)
+      use(i);
+#pragma omp interchange
+    for (int i = 0; i < n; ++i)
+      for (int k = 0; k < n; ++k)
+        use(i + k);
+#pragma omp stripe sizes(4)
+    for (int i = 0; i < n; ++i)
+      use(i);
+#pragma omp fuse
+    {
+      for (int i = 0; i < n; ++i)
+        use(i);
+      for (int k = 0; k < n; ++k)
+        use(k);
+    }
+#pragma omp split counts(2, omp_fill)
+    for (int i = 0; i < n; ++i)
+      use(i);
+  }
+}
+#endif
diff --git a/clang/test/OpenMP/ordered_messages.cpp 
b/clang/test/OpenMP/ordered_messages.cpp
index fb79b07208d10..8575713698647 100644
--- a/clang/test/OpenMP/ordered_messages.cpp
+++ b/clang/test/OpenMP/ordered_messages.cpp
@@ -2,6 +2,7 @@
 // RUN: %clang_cc1 -verify -fopenmp -ferror-limit 100 -std=c++98 -o - %s 
-Wuninitialized
 // RUN: %clang_cc1 -verify -fopenmp -ferror-limit 100 -std=c++11 -o - %s 
-Wuninitialized
 // RUN: %clang_cc1 -verify=expected,omp52 -fopenmp -fopenmp-version=52 
-ferror-limit 100 -o - %s -Wuninitialized
+// RUN: %clang_cc1 -verify=expected,omp52 -fopenmp -fopenmp-version=60 
-ferror-limit 100 -o - %s -Wuninitialized
 
 // RUN: %clang_cc1 -verify -fopenmp-simd -ferror-limit 100 -o - %s 
-Wuninitialized
 // RUN: %clang_cc1 -verify -fopenmp-simd -ferror-limit 100 -std=c++98 -o - %s 
-Wuninitialized
diff --git a/clang/test/OpenMP/simd_loop_transformation_messages.cpp 
b/clang/test/OpenMP/simd_loop_transformation_messages.cpp
deleted file mode 100644
index ebff3da6bf592..0000000000000
--- a/clang/test/OpenMP/simd_loop_transformation_messages.cpp
+++ /dev/null
@@ -1,89 +0,0 @@
-// RUN: %clang_cc1 -fsyntax-only -fopenmp -fopenmp-version=51 \
-// RUN:   -triple x86_64-unknown-unknown -verify=expected,omp5x %s
-// RUN: %clang_cc1 -fsyntax-only -fopenmp -fopenmp-version=52 \
-// RUN:   -triple x86_64-unknown-unknown -verify=expected,omp5x %s
-// RUN: %clang_cc1 -fsyntax-only -fopenmp -fopenmp-version=60 \
-// RUN:   -triple x86_64-unknown-unknown -verify=expected,omp60 %s
-
-// RUN: %clang_cc1 -fsyntax-only -fopenmp-simd -fopenmp-version=51 \
-// RUN:   -triple x86_64-unknown-unknown -verify=expected,omp5x %s
-// RUN: %clang_cc1 -fsyntax-only -fopenmp-simd -fopenmp-version=52 \
-// RUN:   -triple x86_64-unknown-unknown -verify=expected,omp5x %s
-// RUN: %clang_cc1 -fsyntax-only -fopenmp-simd -fopenmp-version=60 \
-// RUN:   -triple x86_64-unknown-unknown -verify=expected,omp60 %s
-
-// OpenMP 6.0 allows simdizable constructs, which include all loop-transforming
-// constructs, to be encountered during execution of a simd region. Earlier
-// versions do not.
-
-void use(int);
-
-void tile_in_simd(int n) {
-#pragma omp simd
-  for (int j = 0; j < n; ++j) {
-    // omp5x-error@+1 {{scan, or atomic directive}}
-#pragma omp tile sizes(4)
-    for (int i = 0; i < n; ++i)
-      use(i);
-  }
-}
-
-void unroll_in_simd(int n) {
-#pragma omp simd
-  for (int j = 0; j < n; ++j) {
-    // omp5x-error@+1 {{scan, or atomic directive}}
-#pragma omp unroll partial(2)
-    for (int i = 0; i < n; ++i)
-      use(i);
-  }
-}
-
-void tile_in_for_simd(int n) {
-#pragma omp for simd
-  for (int j = 0; j < n; ++j) {
-    // omp5x-error@+1 {{scan, or atomic directive}}
-#pragma omp tile sizes(4)
-    for (int i = 0; i < n; ++i)
-      use(i);
-  }
-}
-
-// Constructs that are not simdizable are still rejected in OpenMP 6.0.
-void parallel_in_simd(int n) {
-#pragma omp simd
-  for (int j = 0; j < n; ++j) {
-    // omp5x-error@+2 {{scan, or atomic directive}}
-    // omp60-error@+1 {{atomic, or loop-transforming directive}}
-#pragma omp parallel
-    use(j);
-  }
-}
-
-#if _OPENMP >= 202411
-// Loop-transforming constructs introduced in OpenMP 6.0.
-void omp60_transformations_in_simd(int n) {
-#pragma omp simd
-  for (int j = 0; j < n; ++j) {
-#pragma omp reverse
-    for (int i = 0; i < n; ++i)
-      use(i);
-#pragma omp interchange
-    for (int i = 0; i < n; ++i)
-      for (int k = 0; k < n; ++k)
-        use(i + k);
-#pragma omp stripe sizes(4)
-    for (int i = 0; i < n; ++i)
-      use(i);
-#pragma omp fuse
-    {
-      for (int i = 0; i < n; ++i)
-        use(i);
-      for (int k = 0; k < n; ++k)
-        use(k);
-    }
-#pragma omp split counts(2, omp_fill)
-    for (int i = 0; i < n; ++i)
-      use(i);
-  }
-}
-#endif
diff --git a/clang/test/OpenMP/tile_collapse_messages.cpp 
b/clang/test/OpenMP/tile_collapse_messages.cpp
index 2c9cc57d35105..30c9ff4e17d6c 100644
--- a/clang/test/OpenMP/tile_collapse_messages.cpp
+++ b/clang/test/OpenMP/tile_collapse_messages.cpp
@@ -47,7 +47,7 @@ void collapse_into_stacked_tiles() {
 void collapse_simd_over_tile() {
   // Rejected by the pre-existing restriction on nesting inside a 'simd' 
region.
 #pragma omp simd collapse(2)
-  // expected-error@+1 {{OpenMP constructs may not be nested inside a simd 
region except for ordered simd, simd, scan, or atomic directive}}
+  // expected-error@+1 {{OpenMP constructs may not be nested inside a simd 
region except for ordered simd, simd, scan, atomic, or loop directive}}
 #pragma omp tile sizes(4)
   for (int i = 0; i < 6; ++i)
     body(i);

>From 030b680971bb154a6e9b541e497ec460112434fd Mon Sep 17 00:00:00 2001
From: Zahira Ammarguellat <[email protected]>
Date: Tue, 20 Oct 2026 08:53:48 -0700
Subject: [PATCH 3/3] Applied suggestions

---
 clang/include/clang/Basic/OpenMPKinds.h | 2 ++
 clang/lib/Basic/OpenMPKinds.cpp         | 3 +++
 clang/lib/Sema/SemaOpenMP.cpp           | 8 ++------
 3 files changed, 7 insertions(+), 6 deletions(-)

diff --git a/clang/include/clang/Basic/OpenMPKinds.h 
b/clang/include/clang/Basic/OpenMPKinds.h
index 4515efdf663ec..5e94b4fa582b2 100644
--- a/clang/include/clang/Basic/OpenMPKinds.h
+++ b/clang/include/clang/Basic/OpenMPKinds.h
@@ -520,10 +520,12 @@ bool 
isOpenMPOrderConcurrentNestableDirective(OpenMPDirectiveKind DKind,
 /// Checks if the specified directive is a simdizable directive, i.e. a
 /// directive that may be encountered during execution of a simd region.
 /// \param DKind Specified directive.
+/// \param BindKind Binding of a loop directive; ignored for other directives.
 /// \param LangOpts Used for getting the OpenMP version.
 /// \return true - if the above condition is met for this directive
 /// otherwise - false.
 bool isOpenMPSimdizableDirective(OpenMPDirectiveKind DKind,
+                                 OpenMPBindClauseKind BindKind,
                                  const LangOptions &LangOpts);
 }
 
diff --git a/clang/lib/Basic/OpenMPKinds.cpp b/clang/lib/Basic/OpenMPKinds.cpp
index ca06fe6225328..8049e5d7c1be9 100644
--- a/clang/lib/Basic/OpenMPKinds.cpp
+++ b/clang/lib/Basic/OpenMPKinds.cpp
@@ -947,7 +947,10 @@ bool clang::isOpenMPOrderConcurrentNestableDirective(
 }
 
 bool clang::isOpenMPSimdizableDirective(OpenMPDirectiveKind DKind,
+                                        OpenMPBindClauseKind BindKind,
                                         const LangOptions &LangOpts) {
+  if (DKind == OMPD_loop) // binding region undefined: bind(thread)
+    return BindKind == OMPC_BIND_thread;
   // Directives that may be encountered during execution of a simd region are:
   // OpenMP 5.x: ordered simd, simd, scan and atomic
   // OpenMP 6.0: above plus all loop-transformation directives
diff --git a/clang/lib/Sema/SemaOpenMP.cpp b/clang/lib/Sema/SemaOpenMP.cpp
index 3b1966a50baed..f0b6dc7430bbf 100644
--- a/clang/lib/Sema/SemaOpenMP.cpp
+++ b/clang/lib/Sema/SemaOpenMP.cpp
@@ -5417,12 +5417,8 @@ static bool checkNestingOfRegions(Sema &SemaRef, const 
DSAStackTy *Stack,
   // encountered during execution of an enclosing simd region.
   if (Stack->isInSimdRegion() &&
       ((OMPVersion <= 45 && CurrentRegion != OMPD_ordered_blockassoc) ||
-       (OMPVersion >= 50 &&
-        !isOpenMPSimdizableDirective(CurrentRegion, SemaRef.LangOpts) &&
-        // The loop construct is simdizable if and only if its binding region
-        // is not defined: no bind clause, or bind(thread).
-        !(CurrentRegion == OMPD_loop &&
-          (BindKind == OMPC_BIND_unknown || BindKind == OMPC_BIND_thread))))) {
+       (OMPVersion >= 50 && !isOpenMPSimdizableDirective(
+                                CurrentRegion, BindKind, SemaRef.LangOpts)))) {
     // OpenMP [2.16, Nesting of Regions]
     // OpenMP constructs may not be nested inside a simd region.
     // OpenMP [2.8.1,simd Construct, Restrictions]

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

Reply via email to