openmp: Add support for firstprivate and allocate clauses on scope construct

OpenMP 5.2 adds support for firstprivate and allocate clauses on the scope
construct and this patch adds that support to GCC.
5.2 unfortunately (IMNSHO mistakenly) marked scope construct as worksharing,
which implies that it isn't possible to nest inside of it other scope,
worksharing loop, sections, explicit barriers, single etc. which would
make scope far less useful.  I'm not implementing that part, keeping the
5.1 behavior here, and will file an issue to revert that for OpenMP 6.0.
But, for firstprivate it keeps the restriction that is now implied from
worksharing construct that listed var can't be private in outer context,
where for reduction 5.1 had similar restriction explicit even for scope
and 5.2 has it implicitly through worksharing construct.

2022-05-31  Jakub Jelinek  <jakub@redhat.com>

gcc/
	* omp-low.cc (build_outer_var_ref): For code == OMP_CLAUSE_ALLOCATE
	allow var to be private in the outer context.
	(lower_private_allocate): Pass OMP_CLAUSE_ALLOCATE as last argument
	to build_outer_var_ref.
gcc/c/
	* c-parser.cc (OMP_SCOPE_CLAUSE_MASK): Add firstprivate and allocate
	clauses.
gcc/cp/
	* parser.cc (OMP_SCOPE_CLAUSE_MASK): Add firstprivate and allocate
	clauses.
gcc/testsuite/
	* c-c++-common/gomp/scope-5.c: New test.
	* c-c++-common/gomp/scope-6.c: New test.
	* g++.dg/gomp/attrs-1.C (bar): Add firstprivate and allocate clauses
	to scope construct.
	* g++.dg/gomp/attrs-2.C (bar): Likewise.
libgomp/
	* testsuite/libgomp.c-c++-common/allocate-1.c (foo): Add testcase for
	scope construct with allocate clause.
	* testsuite/libgomp.c-c++-common/allocate-3.c (foo): Likewise.
	* testsuite/libgomp.c-c++-common/scope-2.c: New test.
This commit is contained in:
Jakub Jelinek 2022-05-31 11:41:52 +02:00
parent 0f4df800b1
commit f38b20d68f
10 changed files with 171 additions and 7 deletions

View File

@ -20413,7 +20413,9 @@ c_parser_omp_single (location_t loc, c_parser *parser, bool *if_p)
#define OMP_SCOPE_CLAUSE_MASK \ #define OMP_SCOPE_CLAUSE_MASK \
( (OMP_CLAUSE_MASK_1 << PRAGMA_OMP_CLAUSE_PRIVATE) \ ( (OMP_CLAUSE_MASK_1 << PRAGMA_OMP_CLAUSE_PRIVATE) \
| (OMP_CLAUSE_MASK_1 << PRAGMA_OMP_CLAUSE_FIRSTPRIVATE) \
| (OMP_CLAUSE_MASK_1 << PRAGMA_OMP_CLAUSE_REDUCTION) \ | (OMP_CLAUSE_MASK_1 << PRAGMA_OMP_CLAUSE_REDUCTION) \
| (OMP_CLAUSE_MASK_1 << PRAGMA_OMP_CLAUSE_ALLOCATE) \
| (OMP_CLAUSE_MASK_1 << PRAGMA_OMP_CLAUSE_NOWAIT)) | (OMP_CLAUSE_MASK_1 << PRAGMA_OMP_CLAUSE_NOWAIT))
static tree static tree

View File

@ -43747,7 +43747,9 @@ cp_parser_omp_single (cp_parser *parser, cp_token *pragma_tok, bool *if_p)
#define OMP_SCOPE_CLAUSE_MASK \ #define OMP_SCOPE_CLAUSE_MASK \
( (OMP_CLAUSE_MASK_1 << PRAGMA_OMP_CLAUSE_PRIVATE) \ ( (OMP_CLAUSE_MASK_1 << PRAGMA_OMP_CLAUSE_PRIVATE) \
| (OMP_CLAUSE_MASK_1 << PRAGMA_OMP_CLAUSE_FIRSTPRIVATE) \
| (OMP_CLAUSE_MASK_1 << PRAGMA_OMP_CLAUSE_REDUCTION) \ | (OMP_CLAUSE_MASK_1 << PRAGMA_OMP_CLAUSE_REDUCTION) \
| (OMP_CLAUSE_MASK_1 << PRAGMA_OMP_CLAUSE_ALLOCATE) \
| (OMP_CLAUSE_MASK_1 << PRAGMA_OMP_CLAUSE_NOWAIT)) | (OMP_CLAUSE_MASK_1 << PRAGMA_OMP_CLAUSE_NOWAIT))
static tree static tree

View File

@ -683,6 +683,7 @@ build_outer_var_ref (tree var, omp_context *ctx,
else if ((gimple_code (ctx->stmt) == GIMPLE_OMP_FOR else if ((gimple_code (ctx->stmt) == GIMPLE_OMP_FOR
&& gimple_omp_for_kind (ctx->stmt) == GF_OMP_FOR_KIND_SIMD) && gimple_omp_for_kind (ctx->stmt) == GF_OMP_FOR_KIND_SIMD)
|| ctx->loop_p || ctx->loop_p
|| code == OMP_CLAUSE_ALLOCATE
|| (code == OMP_CLAUSE_PRIVATE || (code == OMP_CLAUSE_PRIVATE
&& (gimple_code (ctx->stmt) == GIMPLE_OMP_FOR && (gimple_code (ctx->stmt) == GIMPLE_OMP_FOR
|| gimple_code (ctx->stmt) == GIMPLE_OMP_SECTIONS || gimple_code (ctx->stmt) == GIMPLE_OMP_SECTIONS
@ -4849,7 +4850,7 @@ lower_private_allocate (tree var, tree new_var, tree &allocator,
allocator = TREE_PURPOSE (allocator); allocator = TREE_PURPOSE (allocator);
} }
if (TREE_CODE (allocator) != INTEGER_CST) if (TREE_CODE (allocator) != INTEGER_CST)
allocator = build_outer_var_ref (allocator, ctx); allocator = build_outer_var_ref (allocator, ctx, OMP_CLAUSE_ALLOCATE);
allocator = fold_convert (pointer_sized_int_node, allocator); allocator = fold_convert (pointer_sized_int_node, allocator);
if (TREE_CODE (allocator) != INTEGER_CST) if (TREE_CODE (allocator) != INTEGER_CST)
{ {

View File

@ -0,0 +1,9 @@
/* { dg-do compile } */
void
foo ()
{
int f = 0;
#pragma omp scope firstprivate(f) /* { dg-error "firstprivate variable 'f' is private in outer context" } */
f++;
}

View File

@ -0,0 +1,31 @@
typedef enum omp_allocator_handle_t
#if __cplusplus >= 201103L
: __UINTPTR_TYPE__
#endif
{
omp_null_allocator = 0,
omp_default_mem_alloc = 1,
omp_large_cap_mem_alloc = 2,
omp_const_mem_alloc = 3,
omp_high_bw_mem_alloc = 4,
omp_low_lat_mem_alloc = 5,
omp_cgroup_mem_alloc = 6,
omp_pteam_mem_alloc = 7,
omp_thread_mem_alloc = 8,
__omp_allocator_handle_t_max__ = __UINTPTR_MAX__
} omp_allocator_handle_t;
int a = 0, b = 42, c = 0;
void
foo (omp_allocator_handle_t h)
{
#pragma omp scope private (a) private (b) reduction (+: c) allocate (allocator (h): a, b, c)
{
if (b != 42)
__builtin_abort ();
a = 36;
b = 15;
c++;
}
}

View File

@ -593,9 +593,11 @@ bar (int d, int m, int i1, int i2, int i3, int p, int *idp, int hda, int s,
[[omp::directive (cancellation point parallel)]]; [[omp::directive (cancellation point parallel)]];
} }
} }
[[omp::directive (scope private (p) reduction(+:r) nowait)]] [[omp::directive (scope private (p) firstprivate (f) reduction(+:r) nowait
allocate (omp_default_mem_alloc: r))]]
; ;
[[omp::directive (scope private (p) reduction(task, +:r))]] [[omp::directive (scope private (p) firstprivate (f) reduction(task, +:r)
allocate (omp_default_mem_alloc: f))]]
; ;
extern int t2; extern int t2;
[[omp::directive (threadprivate (t2))]]; [[omp::directive (threadprivate (t2))]];

View File

@ -593,9 +593,11 @@ bar (int d, int m, int i1, int i2, int i3, int p, int *idp, int hda, int s,
[[omp::directive (cancellation point, parallel)]]; [[omp::directive (cancellation point, parallel)]];
} }
} }
[[omp::directive (scope, private (p), reduction(+:r), nowait)]] [[omp::directive (scope, private (p), firstprivate (f), reduction(+:r), nowait,
allocate(omp_default_mem_alloc: r))]]
; ;
[[using omp:directive (scope, private (p), reduction(task, +:r))]] [[using omp:directive (scope, private (p), firstprivate (f), reduction(task, +:r),
allocate (omp_default_mem_alloc: f))]]
; ;
extern int t2; extern int t2;
[[omp::directive (threadprivate (t2))]]; [[omp::directive (threadprivate (t2))]];

View File

@ -11,7 +11,7 @@ foo (int x, int *p, int *q, int px, omp_allocator_handle_t h, int fl)
int i2, j2, n2 = 9, l4; int i2, j2, n2 = 9, l4;
int i3, j3, n3 = 10, l5; int i3, j3, n3 = 10, l5;
int i4, j4, n4 = 11, l6; int i4, j4, n4 = 11, l6;
int i5; int i5, n5;
int v[x], w[x]; int v[x], w[x];
int r2[4] = { 0, 0, 0, 0 }; int r2[4] = { 0, 0, 0, 0 };
int xo = x; int xo = x;
@ -214,6 +214,34 @@ foo (int x, int *p, int *q, int px, omp_allocator_handle_t h, int fl)
|| q[0] != 3 * (32 * 31) / 2 || q[2] != 4 * (32 * 31) / 2 || q[0] != 3 * (32 * 31) / 2 || q[2] != 4 * (32 * 31) / 2
|| r2[0] != 5 * (32 * 31) / 2 || r2[3] != 6 * (32 * 31) / 2) || r2[0] != 5 * (32 * 31) / 2 || r2[3] != 6 * (32 * 31) / 2)
abort (); abort ();
r = 0;
x = xo;
#pragma omp parallel shared (x, y, r, n5) firstprivate (h)
{
#pragma omp masked
n5 = omp_get_num_threads ();
#pragma omp scope private (y) firstprivate (x) reduction(+:r) \
allocate (h: x, y, r)
{
int *volatile p1 = &x;
int *volatile p2 = &y;
int *volatile p3 = &r;
if (x != 42)
abort ();
#pragma omp barrier
*p2 = 1;
p1[0]++;
p3[0]++;
#pragma omp barrier
if (x != 43 || y != 1 || r != 1)
abort ();
if ((fl & 1) && (((uintptr_t) p1 | (uintptr_t) p2
| (uintptr_t) p3) & 63) != 0)
abort ();
}
}
if (x != 42 || r != n5)
abort ();
} }
void void

View File

@ -11,7 +11,7 @@ foo (int x, int *p, int *q, int px, omp_allocator_handle_t h, int fl)
int i2, j2, n2 = 9, l4; int i2, j2, n2 = 9, l4;
int i3, j3, n3 = 10, l5; int i3, j3, n3 = 10, l5;
int i4, j4, n4 = 11, l6; int i4, j4, n4 = 11, l6;
int i5; int i5, n5;
int v[x], w[x]; int v[x], w[x];
int r2[4] = { 0, 0, 0, 0 }; int r2[4] = { 0, 0, 0, 0 };
int xo = x; int xo = x;
@ -244,6 +244,39 @@ foo (int x, int *p, int *q, int px, omp_allocator_handle_t h, int fl)
|| q[0] != 3 * (32 * 31) / 2 || q[2] != 4 * (32 * 31) / 2 || q[0] != 3 * (32 * 31) / 2 || q[2] != 4 * (32 * 31) / 2
|| r2[0] != 5 * (32 * 31) / 2 || r2[3] != 6 * (32 * 31) / 2) || r2[0] != 5 * (32 * 31) / 2 || r2[3] != 6 * (32 * 31) / 2)
abort (); abort ();
r = 0;
x = xo;
#pragma omp parallel shared (x, y, r, n5) firstprivate (h)
{
#pragma omp masked
n5 = omp_get_num_threads ();
#pragma omp scope private (y) firstprivate (x) reduction(+:r) \
allocate (allocator (h), align (32): x) \
allocate (align (128), allocator (h): y) \
allocate (align (32), allocator (h): r)
{
int *volatile p1 = &x;
int *volatile p2 = &y;
if (x != 42)
abort ();
#pragma omp barrier
*p2 = 1;
p1[0]++;
r++;
#pragma omp barrier
if (x != 43 || y != 1 || r != 1)
abort ();
if ((fl & 1) && (((uintptr_t) p1 | (uintptr_t) p2
| (uintptr_t) &r) & 63) != 0)
abort ();
if ((((uintptr_t) p1 | (uintptr_t) &r) & 31) != 0)
abort ();
if ((((uintptr_t) p2) & 127) != 0)
abort ();
}
}
if (x != 42 || r != n5)
abort ();
} }
void void

View File

@ -0,0 +1,54 @@
#ifdef __cplusplus
extern "C"
#endif
void abort ();
int
main ()
{
int a[64] = {};
int r = 0, r2 = 0, i, n = 64;
#pragma omp parallel
{
#pragma omp scope nowait
#pragma omp scope nowait firstprivate (n)
#pragma omp for
for (i = 0; i < 64; i++)
a[i] += 1;
#pragma omp scope reduction(+: r) nowait firstprivate (n)
{
#pragma omp for nowait
for (i = 0; i < 64; i++)
{
r += i;
if (a[i] != 1)
abort ();
}
#pragma omp barrier
if (n != 64)
abort ();
else
n = 128;
}
#pragma omp barrier
if (r != 64 * 63 / 2)
abort ();
#pragma omp scope nowait private (i)
#pragma omp scope reduction(+: r2)
{
#pragma omp for nowait
for (i = 0; i < 64; i++)
{
r2 += 2 * i;
a[i] += i;
}
}
if (r2 != 64 * 63)
abort ();
#pragma omp for nowait
for (i = 0; i < 64; i++)
if (a[i] != i + 1)
abort ();
}
return 0;
}