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/2] [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/2] 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); _______________________________________________ cfe-commits mailing list [email protected] https://lists.llvm.org/cgi-bin/mailman/listinfo/cfe-commits
