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.fpp — GPU_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:
-
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
-
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.
Summary
no_createis a documented parameter of three public GPU macros —GPU_PARALLEL,GPU_PARALLEL_LOOP, andGPU_DATA— and is fully implemented on the OpenACC side. ButOMP_NOCREATE_STRunconditionally aborts fypp when it is set, and becauseGPU_PARALLEL_LOOPbuilds both the ACC and OMP directive strings before the#ifselects one, passingno_createis 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.fpp—GPU_PARALLEL(line 8),GPU_PARALLEL_LOOP(line 28),GPU_DATA(line 122).Implemented for OpenACC in
src/common/include/acc_macros.fpp:28:Refused for OpenMP in
src/common/include/omp_macros.fpp:69:The reason a
#:stophere breaks an ACC build is thatGPU_PARALLEL_LOOPevaluates both backends eagerly (parallel_macros.fpp:30-35):#ifis a Fortran preprocessor conditional resolved by the compiler, long after fypp has already had to evaluate both#:setright-hand sides. So the OpenMP#:stopfires for OpenACC builds too.Reproduction
/tmp/nc.fpp:Expanded with the same flags the build uses (
cmake/Fypp.cmake), and with onlyMFC_SIMULATIONdefined — no OpenMP anywhere:Removing only
no_create='[a]'from that same file succeeds (exit 0) and emits:It also fails through the real build. Adding
no_create='[pb_in, mv_in]'to theGPU_PARALLEL_LOOPins_ibm_correct_state(src/simulation/m_ibm.fpp:222) and running./mfc.sh build -t simulation --gpu accon Frontier gives: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 intoomp_macros.fpprather than at their call site.I hit this reaching for
no_createwhile investigating an unrelated CCE 21 issue on Frontier, on a--gpu accbuild.Suggested fix
Either of:
Make the OpenMP path a no-op with a comment. OpenMP 5.x has no exact
no_createequivalent, and MFC already defaults todefault(present)/defaultmap(present:allocatable), so emitting nothing is the closest safe behaviour and keeps the ACC implementation reachable:Remove
no_createfrom the three public signatures so it cannot be reached at all, and dropGEN_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, andpresentfor the same eager-evaluation trap, since they flow through the same#:set-both-then-#ifstructure.