public inbox for gcc-bugs@sourceware.org
help / color / mirror / Atom feed
* [Bug c++/110347] New: [OpenMP] private/firstprivate of a C++ member variable mishandled
@ 2023-06-21 16:24 burnus at gcc dot gnu.org
  2023-06-21 16:28 ` [Bug c++/110347] " burnus at gcc dot gnu.org
                   ` (3 more replies)
  0 siblings, 4 replies; 5+ messages in thread
From: burnus at gcc dot gnu.org @ 2023-06-21 16:24 UTC (permalink / raw)
  To: gcc-bugs

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

^ permalink raw reply	[flat|nested] 5+ messages in thread

end of thread, other threads:[~2024-03-01 16:31 UTC | newest]

Thread overview: 5+ messages (download: mbox.gz / follow: Atom feed)
-- links below jump to the message on this page --
2023-06-21 16:24 [Bug c++/110347] New: [OpenMP] private/firstprivate of a C++ member variable mishandled burnus at gcc dot gnu.org
2023-06-21 16:28 ` [Bug c++/110347] " burnus at gcc dot gnu.org
2023-11-21 13:11 ` burnus at gcc dot gnu.org
2024-03-01 16:27 ` cvs-commit at gcc dot gnu.org
2024-03-01 16:31 ` burnus at gcc dot gnu.org

This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox;
as well as URLs for read-only IMAP folder(s) and NNTP newsgroup(s).