diff --git a/clang/lib/Sema/SemaOpenMP.cpp b/clang/lib/Sema/SemaOpenMP.cpp --- a/clang/lib/Sema/SemaOpenMP.cpp +++ b/clang/lib/Sema/SemaOpenMP.cpp @@ -4975,9 +4975,13 @@ // omp_get_num_teams() regions, and omp_get_team_num() regions are the // only OpenMP regions that may be strictly nested inside the teams // region. + // + // As an extension, we permit atomic within teams as well. NestingProhibited = !isOpenMPParallelDirective(CurrentRegion) && !isOpenMPDistributeDirective(CurrentRegion) && - CurrentRegion != OMPD_loop; + CurrentRegion != OMPD_loop && + !(SemaRef.getLangOpts().OpenMPExtensions && + CurrentRegion == OMPD_atomic); Recommend = ShouldBeInParallelRegion; } if (!NestingProhibited && CurrentRegion == OMPD_loop) { diff --git a/clang/test/OpenMP/nesting_of_regions.cpp b/clang/test/OpenMP/nesting_of_regions.cpp --- a/clang/test/OpenMP/nesting_of_regions.cpp +++ b/clang/test/OpenMP/nesting_of_regions.cpp @@ -1,10 +1,11 @@ -// RUN: %clang_cc1 -fsyntax-only -fopenmp -fopenmp-version=45 -verify=expected,omp45,omp45warn %s -// RUN: %clang_cc1 -fsyntax-only -fopenmp -verify=expected,omp50 %s -// RUN: %clang_cc1 -fsyntax-only -fopenmp -fopenmp-version=45 -verify=expected,omp45 -Wno-openmp %s -// RUN: %clang_cc1 -fsyntax-only -fopenmp -fopenmp-version=45 -verify=expected,omp45 -Wno-source-uses-openmp %s +// RUN: %clang_cc1 -fsyntax-only -fopenmp -fopenmp-version=45 -fno-openmp-extensions -verify=expected,omp45,omp45warn,omp %s +// RUN: %clang_cc1 -fsyntax-only -fopenmp -fno-openmp-extensions -verify=expected,omp50,omp %s +// RUN: %clang_cc1 -fsyntax-only -fopenmp -fopenmp-extensions -verify=expected,omp50 %s +// RUN: %clang_cc1 -fsyntax-only -fopenmp -fopenmp-version=45 -verify=expected,omp45,omp -fno-openmp-extensions -Wno-openmp %s +// RUN: %clang_cc1 -fsyntax-only -fopenmp -fopenmp-version=45 -verify=expected,omp45,omp -fno-openmp-extensions -Wno-source-uses-openmp %s -// RUN: %clang_cc1 -fsyntax-only -fopenmp-simd -fopenmp-version=45 -verify=expected,omp45,omp45warn %s -// RUN: %clang_cc1 -fsyntax-only -fopenmp-simd -verify=expected,omp50 %s +// RUN: %clang_cc1 -fsyntax-only -fopenmp-simd -fopenmp-version=45 -fno-openmp-extensions -verify=expected,omp45,omp45warn,omp %s +// RUN: %clang_cc1 -fsyntax-only -fopenmp-simd -verify=expected,omp50,omp -fno-openmp-extensions %s // SIMD-ONLY0-NOT: {{__kmpc|__tgt}} void bar(); @@ -5264,7 +5265,7 @@ #pragma omp target #pragma omp teams { -#pragma omp atomic // expected-error {{region cannot be closely nested inside 'teams' region; perhaps you forget to enclose 'omp atomic' directive into a parallel region?}} +#pragma omp atomic // omp-error {{region cannot be closely nested inside 'teams' region; perhaps you forget to enclose 'omp atomic' directive into a parallel region?}} ++a; } #pragma omp target @@ -8422,7 +8423,7 @@ } #pragma omp target teams { -#pragma omp atomic // expected-error {{region cannot be closely nested inside 'target teams' region; perhaps you forget to enclose 'omp atomic' directive into a parallel region?}} +#pragma omp atomic // omp-error {{region cannot be closely nested inside 'target teams' region; perhaps you forget to enclose 'omp atomic' directive into a parallel region?}} ++a; } #pragma omp target teams @@ -14096,7 +14097,7 @@ #pragma omp target #pragma omp teams { -#pragma omp atomic // expected-error {{region cannot be closely nested inside 'teams' region; perhaps you forget to enclose 'omp atomic' directive into a parallel region?}} +#pragma omp atomic // omp-error {{region cannot be closely nested inside 'teams' region; perhaps you forget to enclose 'omp atomic' directive into a parallel region?}} ++a; } #pragma omp target @@ -17299,7 +17300,7 @@ } #pragma omp target teams { -#pragma omp atomic // expected-error {{region cannot be closely nested inside 'target teams' region; perhaps you forget to enclose 'omp atomic' directive into a parallel region?}} +#pragma omp atomic // omp-error {{region cannot be closely nested inside 'target teams' region; perhaps you forget to enclose 'omp atomic' directive into a parallel region?}} ++a; } #pragma omp target teams diff --git a/openmp/libomptarget/test/offloading/target-teams-atomic.c b/openmp/libomptarget/test/offloading/target-teams-atomic.c new file mode 100644 --- /dev/null +++ b/openmp/libomptarget/test/offloading/target-teams-atomic.c @@ -0,0 +1,50 @@ +// Check that omp atomic is permitted and behaves when strictly nested within +// omp target teams. This is an extension to OpenMP 5.2 and is enabled by +// default. + +// RUN: %libomptarget-compile-run-and-check-generic + +#include +#include +#include +#include + +// High parallelism increases our chances of detecting a lack of atomicity. +#define NUM_TEAMS_TRY 256 + +int main() { + // CHECK: update: num_teams=[[#NUM_TEAMS:]]{{$}} + // CHECK-NEXT: update: x=[[#NUM_TEAMS]]{{$}} + int x = 0; + int numTeams; + #pragma omp target teams num_teams(NUM_TEAMS_TRY) map(tofrom:x, numTeams) + { + #pragma omp atomic update + ++x; + if (omp_get_team_num() == 0) + numTeams = omp_get_num_teams(); + } + printf("update: num_teams=%d\n", numTeams); + printf("update: x=%d\n", x); + + // CHECK-NEXT: capture: x=[[#NUM_TEAMS]]{{$}} + // CHECK-NEXT: capture: xCapturedCount=[[#NUM_TEAMS]]{{$}} + bool xCaptured[numTeams]; + memset(xCaptured, 0, sizeof xCaptured); + x = 0; + #pragma omp target teams num_teams(NUM_TEAMS_TRY) map(tofrom:x, numTeams) + { + int v; + #pragma omp atomic capture + v = x++; + xCaptured[v] = true; + } + printf("capture: x=%d\n", x); + int xCapturedCount = 0; + for (int i = 0; i < numTeams; ++i) { + if (xCaptured[i]) + ++xCapturedCount; + } + printf("capture: xCapturedCount=%d\n", xCapturedCount); + return 0; +} diff --git a/openmp/runtime/test/teams/teams-atomic.c b/openmp/runtime/test/teams/teams-atomic.c new file mode 100644 --- /dev/null +++ b/openmp/runtime/test/teams/teams-atomic.c @@ -0,0 +1,49 @@ +// Check that omp atomic is permitted and behaves when strictly nested within +// omp teams. This is an extension to OpenMP 5.2 and is enabled by default. + +// RUN: %libomp-compile-and-run | FileCheck %s + +#include +#include +#include +#include + +// High parallelism increases our chances of detecting a lack of atomicity. +#define NUM_TEAMS_TRY 256 + +int main() { + // CHECK: update: num_teams=[[#NUM_TEAMS:]]{{$}} + // CHECK-NEXT: update: x=[[#NUM_TEAMS]]{{$}} + int x = 0; + int numTeams; + #pragma omp teams num_teams(NUM_TEAMS_TRY) + { + #pragma omp atomic update + ++x; + if (omp_get_team_num() == 0) + numTeams = omp_get_num_teams(); + } + printf("update: num_teams=%d\n", numTeams); + printf("update: x=%d\n", x); + + // CHECK-NEXT: capture: x=[[#NUM_TEAMS]]{{$}} + // CHECK-NEXT: capture: xCapturedCount=[[#NUM_TEAMS]]{{$}} + bool xCaptured[numTeams]; + memset(xCaptured, 0, sizeof xCaptured); + x = 0; + #pragma omp teams num_teams(NUM_TEAMS_TRY) + { + int v; + #pragma omp atomic capture + v = x++; + xCaptured[v] = true; + } + printf("capture: x=%d\n", x); + int xCapturedCount = 0; + for (int i = 0; i < numTeams; ++i) { + if (xCaptured[i]) + ++xCapturedCount; + } + printf("capture: xCapturedCount=%d\n", xCapturedCount); + return 0; +}