public inbox for gcc-bugs@sourceware.org
help / color / mirror / Atom feed
* [Bug middle-end/112779] New: [OpenMP] Support omp Metadirectives
@ 2023-11-30 11:14 burnus at gcc dot gnu.org
  0 siblings, 0 replies; only message in thread
From: burnus at gcc dot gnu.org @ 2023-11-30 11:14 UTC (permalink / raw)
  To: gcc-bugs

https://gcc.gnu.org/bugzilla/show_bug.cgi?id=112779

            Bug ID: 112779
           Summary: [OpenMP] Support omp Metadirectives
           Product: gcc
           Version: 14.0
            Status: UNCONFIRMED
          Severity: normal
          Priority: P3
         Component: middle-end
          Assignee: unassigned at gcc dot gnu.org
          Reporter: burnus at gcc dot gnu.org
  Target Milestone: ---

There is a rather complete support for metadirectives on the OG13 branch, i.e.
devel/omp/gcc-13 branch.

Several patches have been already posted.

* * *

Known issues with those patches:

(A) OpenMP 5.2's renaming of clause 'default' is now (also) 'otherwise'

(B) -------------------------------------------
ICE (segfault) for "kind: nohost" in default()

og12-offload/testlogs-2023-05-04 shows several 'internal compiler error:
Segmentation fault' for the 'default' clause of the metadirectives

→ sollve_vv's test_metadirective_target_device{,_kind{,_any}}.c testcases.

The problem for one test case at least is in omp-general.cc's omp_dynamic_cond
:

'kind_sel' = {purpose = "kind", value = "{ purpose: "nohost", value: NULL}" } -
and accessing TREE_VALUE (TREE_VALUE (kind_sel)).

That's for the following code:



      tree kind_sel = omp_get_context_selector (ctx, "target_device", "kind");
      if (kind_sel)
        {
          const char *str
            = (TREE_VALUE (TREE_VALUE (kind_sel))
               ? TREE_STRING_POINTER (TREE_VALUE (TREE_VALUE (kind_sel)))
               : IDENTIFIER_POINTER (TREE_PURPOSE (TREE_VALUE (kind_sel))));
          kind =  build_string_literal (strlen (str) + 1, str);
        } 



I wonder why that's not already handled in gcc/omp-general.cc's
omp_context_selector_matches (which has some code) – but it might indeed only
be available at run time?!?


(C) ------------------------------------------------------

wonder whether libgomp/target.c's GOMP_evaluate_target_device lacks a check for
kind == "nohost" — I only see "host" (for the host) and "gpu" (for the GPU) and
the generic "any".


(D) ---------------------------------------------------------

Fortran's DO with do-end-label{}

Fortran permits loops with label instead of a simple END DO, example:



DO 123 i=1,5
  DO 123 j=1,5
123 CONTINUE  ! or '123 END DO' — Note the *shared* end-do-label (which
invalid/deleted since F2018, before deprecated but valid)

Such code is not handled with metadirectives as already indicated at
gcc/fortran/parse.cc's parse_omp_metadirective_body:





        case_omp_do:
          st = parse_omp_do (clause->stmt);
          /* TODO: Does st == ST_IMPLIED_ENDDO need special handling?  */
          break; 

The answer seems to be yes — failing testcase is the following ("Error: END DO
statement expected"):



implicit none
integer :: i, j, psi(5,5)!$omp  metadirective  &
!$omp&    when(user={condition(.false. )}: target teams  &
!$omp&         distribute parallel do simd collapse(2))  &
!$omp&    when(user={condition(.false. )}: target teams  &
!$omp&         distribute parallel do)  &
!$omp&    default(target teams loop collapse(2))
      DO 50 I=1,5
!$omp  metadirective  &
!$omp& when(user={condition(.false. )}: simd)               
      DO 51 J=1,5
        PSI(j,i) = j
   51 CONTINUE
   50 CONTINUE
end 


(E) -------------------------------------------------------

internal compiler error: in c_parser_omp_metadirective, at c/c-parser.cc:26565
   11 |  #pragma omp metadirective when (user = { condition (USE_GPU == 1) } :
target enter data map(alloc : number[ : SIZE]))

for:

#include <stdio.h>
#include <omp.h>

int main(int argc, char ** argv){

    const int SIZE = 10; 
    int USE_GPU = 1;
    double number[SIZE];
    double *number_d;
 #pragma omp metadirective when (user = { condition (USE_GPU == 1) } : target
enter data map(alloc : number[ : SIZE]))
    if (USE_GPU)
        number_d = (double *)omp_get_mapped_ptr(number,
omp_get_default_device());
    else
        number_d = number;
    printf("number_d = %p    number= %p\n", number_d, number);

    return 0;
}


(F) ----------------------------------------------------------------

For C/C++, begin/end metadirective is not handled - it is for Fortran, where it
is much more useful.

Note: It is less useful that it sounds. From an internal bug tracker:

This was a deliberate design decision. From the OpenMP 5.0 spec (2.3.4):

"The begin metadirective directive behaves identically to the metadirective
directive, except that the directive syntax for the specified directive
variants must accept a paired end directive."

so having 'target enter data' in a 'begin metadirective' is invalid.

The only OpenMP directive supported in GCC that takes an end directive in C/C++
is 'declare target' (is this still true?), and we have already said that we
would not support declarative constructs in metadirectives. So the 'begin/end
metadirective' support was left out in C/C++.

(Invalid) testcase:

#pragma omp begin metadirective  when (user = { condition (USE_GPU == 1) } )
#pragma omp  target enter data map(alloc : number[ : SIZE])
    ;   
#pragma omp end metadirective

I get
$ gcc -O3 -fopenmp -foffload="-march=gfx90a -lm" -lm  ./test_meta_user.c
./test_meta_user.c: In function 'main':
./test_meta_user.c:11:19: error: expected 'declare target' or 'assumes' before
'metadirective'
   11 | #pragma omp begin metadirective  when (user = { condition (USE_GPU ==
1) } )
      |                   ^~~~~~~~~~~~~
./test_meta_user.c:14:17: error: expected 'declare' or 'assumes' before
'metadirective'
   14 | #pragma omp end metadirective
      |                 ^~~~~~~~~~~~~
----------------

Note:
In C/C++, only delimited directives have a begin/end + and only 'begin/end
assumes' seems to be useful.

Details:
Quoting the OpenMP spec (git version; 5.0 and later have similar wording):

"The restrictions to begin metadirective are as follows:
• Any directive-variant that is specified by a when or otherwise clause must be
a directive that has a paired end directive or must be the nothing directive."

(This applies to both Fortran and C/C++, but while in Fortran any structured
block can have an end directive, only a few directives in C/C++ can have an end
directive..)

In case of "target enter data", it is clear that this does not have any paired
end directive - neither in C/C++ nor in Fortran.


Otherwise, OpenMP 5.0 and 5.1 makes it very simple to search for '#pragma omp
end'. This turns up the following directives that have an end-directive in
C/C++:

#pragma omp begin/end metadirective  - OMP 5.0
#pragma omp (end) declare target  - OMP 5.0
#pragma omp begin/end declare target  - OMP 5.1
#pragma omp begin/end declare variant  - OMP 5.1
#pragma omp begin/end assumes  - OMP 5.1


Additionally, there is - quoting 5.1:

"Restrictions to metadirectives are as follows:
• The directive variant appearing in a when or default clause must not specify
a metadirective, begin metadirective, or end metadirective directive.
C / C++
• The directive variant that appears in a when or default clause must not
specify a begin declare variant or end declare variant"


Thus, that leaves for 5.0 only "omp begin declare target" and for/since 5.1
additionally "omp begin assumes".


In 5.2 and later, the restrictions moved to the when and otherwise (=
"default") clauses:

  "directive-variant must not specify a metadirective."
  "directive-variant must not specify a begin declare variant directive"


Additionally, there is:

• If the list of dynamic replacement candidates has multiple items then all
items must be executable directives.

Which in turn disallows declarative directives unless there is a single dynamic
replacement candidate - implying that the dynamic context selector does not
need to be evaluated in that case.


(G) ------------------------------------------------------------

ICE on invalid:

Regarding the following testcase, I believe the following is invalid:

    !$OMP metadirective &
    !$OMP   when ( user = { condition ( UseDevice ) } &
    !$OMP     : end target teams distribute parallel do simd ) &
    !$OMP   default ( end parallel do simd ) 

Namely, neither "end target teams ..." nor "end parallel ..." is a valid
directive-specification — and the latter starts with a valid directive-name –
and "end" isn't one nor is 'end target' nor ...

Hence, I believe that OpenMP requires for directives that require an
end-directive to use metadirective's delimited form, i.e. 'omp begin
metadirective" ... "omp end metadirective".

----------
program OpenMP_Metadirective_WrongEnd_Test
  integer :: &
    iV, jV, kV
  integer, dimension ( 3 ) :: &
    lV, uV
  logical :: &
    UseDevice

    UseDevice = .False.

    !$OMP metadirective &
    !$OMP   when ( user = { condition ( UseDevice ) } &
    !$OMP     : target teams distribute parallel do simd collapse ( 3 ) &
    !$OMP         private ( iaVS ) ) &
    !$OMP   default ( parallel do simd collapse ( 3 ) private ( iaVS ) )
    do kV = lV ( 3 ), uV ( 3 ) 
      do jV = lV ( 2 ), uV ( 2 ) 
        do iV = lV ( 1 ), uV ( 1 ) 


        end do
      end do
    end do
    !$OMP metadirective &
    !$OMP   when ( user = { condition ( UseDevice ) } &
    !$OMP     : end target teams distribute parallel do simd ) &
    !$OMP   default ( end parallel do simd ) 
end program
----------


(H) ---------------------------------------------

The following gives also an ICE:

program test
  implicit none  integer, parameter :: N = 100
  integer :: x(N), y(N), z(N)  block
    integer :: k
    !$omp metadirective &
                !$omp& when(device={arch("nvptx")}: teams loop) &
                !$omp& default(parallel loop)
    do i = 1, N
          z(i) = x(i) * y(i)
    enddo
   end block
end

^ permalink raw reply	[flat|nested] only message in thread

only message in thread, other threads:[~2023-11-30 11:14 UTC | newest]

Thread overview: (only message) (download: mbox.gz / follow: Atom feed)
-- links below jump to the message on this page --
2023-11-30 11:14 [Bug middle-end/112779] New: [OpenMP] Support omp Metadirectives 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).