Skip to content

GPU_PARALLEL_LOOP advertises no_create but OMP_NOCREATE_STR aborts fypp, breaking OpenACC-only builds #1687

Description

@sbryngelson

Summary

no_create is a documented parameter of three public GPU macros — GPU_PARALLEL, GPU_PARALLEL_LOOP, and GPU_DATA — and is fully implemented on the OpenACC side. But OMP_NOCREATE_STR unconditionally aborts fypp when it is set, and because GPU_PARALLEL_LOOP builds both the ACC and OMP directive strings before the #if selects one, passing no_create is a fatal build error even in an OpenACC-only build, where the working ACC implementation would have been used.

Net effect: a parameter that appears available in the public macro API cannot be used by anyone, on any backend.

Where

Exposed in src/common/include/parallel_macros.fppGPU_PARALLEL (line 8), GPU_PARALLEL_LOOP (line 28), GPU_DATA (line 122).

Implemented for OpenACC in src/common/include/acc_macros.fpp:28:

#:def GEN_NOCREATE_STR(no_create)
    #:set nocreate_val = GEN_PARENTHESES_CLAUSE('no_create', no_create)

Refused for OpenMP in src/common/include/omp_macros.fpp:69:

#:def OMP_NOCREATE_STR(no_create)
    #:if no_create is not None
        #:stop 'no_create is not supported yet'
    #:endif
    #:set no_create_val = ''
    $:no_create_val

The reason a #:stop here breaks an ACC build is that GPU_PARALLEL_LOOP evaluates both backends eagerly (parallel_macros.fpp:30-35):

    #:set acc_directive = ACC_PARALLEL_LOOP(collapse, private, ..., no_create, ...)
    #:set omp_directive = OMP_PARALLEL_LOOP(collapse, private, ..., no_create, ...)   ! evaluated regardless

#if defined(MFC_OpenACC)
    $:acc_directive
#elif defined(MFC_OpenMP)
    $:omp_directive
#endif

#if is a Fortran preprocessor conditional resolved by the compiler, long after fypp has already had to evaluate both #:set right-hand sides. So the OpenMP #:stop fires for OpenACC builds too.

Reproduction

/tmp/nc.fpp:

#:include 'parallel_macros.fpp'
subroutine s_t(a, n)
    integer, intent(in) :: n
    real, intent(inout) :: a(n)
    integer :: i
    $:GPU_PARALLEL_LOOP(private='[i]', no_create='[a]')
    do i = 1, n
        a(i) = a(i) + 1.0
    end do
    $:END_GPU_PARALLEL_LOOP()
end subroutine

Expanded with the same flags the build uses (cmake/Fypp.cmake), and with only MFC_SIMULATION defined — no OpenMP anywhere:

$ fypp -m re -I src/common/include -I src/common \
       -D MFC_Cray -D MFC_SIMULATION -D 'MFC_COMPILER="Cray"' \
       -D MFC_CASE_OPTIMIZATION=False -D chemistry=False  /tmp/nc.fpp /tmp/nc.f90

src/common/include/omp_macros.fpp:166: error: exception occurred when setting
  variable(s) 'no_create_val' to 'OMP_NOCREATE_STR(no_create)' [FyppFatalError]
src/common/include/omp_macros.fpp:71: error: no_create is not supported yet [FyppStopRequest]
$ echo $?
1

Removing only no_create='[a]' from that same file succeeds (exit 0) and emits:

!$acc parallel loop gang vector default(present) private(i)

It also fails through the real build. Adding no_create='[pb_in, mv_in]' to the GPU_PARALLEL_LOOP in s_ibm_correct_state (src/simulation/m_ibm.fpp:222) and running ./mfc.sh build -t simulation --gpu acc on Frontier gives:

222-225: error: exception occurred when evaluating 'GPU_PARALLEL_LOOP(... no_create='[pb_in, mv_in]')' [FyppFatalError]
omp_macros.fpp:71: error: no_create is not supported yet [FyppStopRequest]
gmake[3]: *** [CMakeFiles/simulation.dir/.../m_ibm.fpp.f90] Error 1

Impact

Latent rather than currently breaking: no call site in the tree uses no_create, which is presumably why it has gone unnoticed. The cost is paid by the next person who reaches for it — the parameter is in the signature, correct for their backend, and detonates with an error that points into omp_macros.fpp rather than at their call site.

I hit this reaching for no_create while investigating an unrelated CCE 21 issue on Frontier, on a --gpu acc build.

Suggested fix

Either of:

  1. Make the OpenMP path a no-op with a comment. OpenMP 5.x has no exact no_create equivalent, and MFC already defaults to default(present) / defaultmap(present:allocatable), so emitting nothing is the closest safe behaviour and keeps the ACC implementation reachable:

    #:def OMP_NOCREATE_STR(no_create)
        #! OpenMP has no no_create equivalent; the mapping is already
        #! present-by-default, so emit nothing rather than aborting fypp.
        #:set no_create_val = ''
        $:no_create_val
    #:enddef
    
  2. Remove no_create from the three public signatures so it cannot be reached at all, and drop GEN_NOCREATE_STR.

(1) is preferable if the ACC clause is wanted; (2) if it is not. Either way the current state — advertised, half-implemented, fatal on both backends — is the worst of the three.

Worth checking create, attach, deviceptr, and present for the same eager-evaluation trap, since they flow through the same #:set-both-then-#if structure.

Metadata

Metadata

Assignees

No one assigned

    Labels

    Type

    No type

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions