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};