https://gcc.gnu.org/bugzilla/show_bug.cgi?id=110347
Bug ID: 110347
Summary: [OpenMP] private/firstprivate of a C++ member variable
mishandled
Product: gcc
Version: 14.0
Status: UNCONFIRMED
Keywords: ice-on-valid-code, openmp, wrong-code
Severity: normal
Priority: P3
Component: c++
Assignee: unassigned at gcc dot gnu.org
Reporter: burnus at gcc dot gnu.org
CC: jakub at gcc dot gnu.org
Target Milestone: ---
On the GCC side, this came up at
https://gcc.gnu.org/pipermail/gcc-patches/2022-June/596238.html
It was also discussed at length but with a different focus in a couple of
base-language OpenMP spec meetings, albeit Tom was only in one. I did not
quickly find an associated issue, maybe it was only shown on screen without an
associated issue by Kelvin or Deepak. ... I found the OpenMP spec issue → #3343
(see last comment for the result when Tom was there; I filed the issue based on
a previous discussion.)
Currently, we have for (assume a prior enter-data mapping of this[:1] if it
helps):
------------
struct C {
int a, b, c, d;
void foo (void) {
#pragma omp target private (a) firstprivate(b)
{ a = 1; b = 2; c = 3; this->d = 4; }
}
};
int main() { C c; c.foo(); }
------------
the original dump
------------
{
int D.2925 [value-expr: ((struct C *) this)->a];
int D.2924 [value-expr: ((struct C *) this)->b];
#pragma omp target map(tofrom:*(struct C *) this [len: 16])
map(firstprivate:(struct C *) this [pointer assign, bias: 0])
firstprivate(D.2924) private(D.2925)
{
{
<<cleanup_point <<< Unknown tree: expr_stmt
(void) (D.2925 = 1) >>>>>;
<<cleanup_point <<< Unknown tree: expr_stmt
(void) (D.2924 = 2) >>>>>;
<<cleanup_point <<< Unknown tree: expr_stmt
(void) (((struct C *) this)->c = 3) >>>>>;
<<cleanup_point <<< Unknown tree: expr_stmt
(void) (((struct C *) this)->d = 4) >>>>>;
}
}
}
------------
the gimple dump
------------
void C::foo (struct C * const this)
{
int a [value-expr: this->a];
int b [value-expr: this->b];
#pragma omp target num_teams(-2) thread_limit(0) map(tofrom:this [len:
8][implicit]) map(tofrom:*this [len: 16]) map(firstprivate:this [pointer
assign, bias: 0]) firstprivate(b) private(a)
{
this->a = 1;
this->b = 2;
this->c = 3;
this->d = 4;
}
}
------------
If I have understood the discussions and rules correctly, the expected result
would be:
{
int D.2925;
int D.2924 = ((struct C *) this)->b;
#pragma omp target map(tofrom:*(struct C *) this [len: 16])
map(firstprivate:(struct C *) this [pointer assign, bias: 0])
firstprivate(D.2924) private(D.2925)
{
{
D.2925 = 1;
D.2924 = 2;
((struct C *) this)->c = 3;
((struct C *) this)->d = 4;
}
}
}
* * *
In terms of the spec, the following takes care of the
'firstprivate(cpp_member_var)' as it wouldn't be otherwise permitted in a
firstprivate:
"--- C++ ---
Unless otherwise specified, a variable that is part of another variable (as an
array element or a structure element) cannot be a variable list item, an
extended list item or locator list item except if the list appears on a clause
that is associated with a construct within a class non-static member function
and the variable is an accessible data member of the object for which the
non-static member function is invoked."
[OpenMP 5.2, 3.2.1 OpenMP Argument Lists [62:1-5])
Otherwise, if a clause should permit to use array sections or
structure-components as list item, that clause needs to explicit permit it. (In
5.2; in 5.1 it was the other way round.)
This wording still does not permit 'firstprivate(this->a)' - only
firstprivate(a).
I assume that for
#pragma omp target map(this[:1]) firstprivate(a)
{ this->a = 5; a = 7; printf("%d %d\n", a, this->a); }
print ("%d\n", a);
the expected result would be: '7 5' and '5'.
* * *
Side remark: The following gives an ICE:
struct C {
int a, b, c, d;
void foo (void) {
#pragma omp target defaultmap(firstprivate)
{ a = 1; b = 2; c = 3; d = 4; }
}
};
Namely:
internal compiler error: in gimplify_adjust_omp_clauses, at gimplify.cc:13004
4 | #pragma omp target defaultmap(firstprivate)
* The ICE is new since GCC12
* GCC12+ accepts also 'map(this[:1])' - with the same ICE.
while GCC11 rejected the latter with:
'error: ‘this’ allowed in OpenMP only in ‘declare simd’ clauses'
* GCC 11 compiles the version above w/o map(this[:1]) and gimplifies it as
defaultmap(firstprivate) firstprivate(this)
and in the optimized dump, GCC 11 then has:
.omp_data_arr.1.this = this_2(D); .omp_data_sizes.2[1] = {0};