1687 fix: Make OpenMP no_create a documented no-op instead of aborting fypp. - #1724
Conversation
OMP_NOCREATE_STR called #:stop whenever no_create was set. GPU_PARALLEL, GPU_PARALLEL_LOOP and GPU_DATA expand both the ACC and OMP directive strings at fypp time and let the compile-time #if select one, so the abort fired on OpenACC-only builds too -- making a documented parameter unusable on every backend. OpenMP has no no_create equivalent, and OMP_DEFAULT_STR already emits a present-by-default mapping, so emitting nothing is the closest safe behavior. Document the clause as OpenACC-only, matching the existing GPU_CACHE note. Generated Fortran is byte-identical across all 109 .fpp files in the three targets: every call site passes no_create=None, which already took the empty-string path. Closes MFlowCode#1687 Co-Authored-By: Claude Opus 5 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_016xc51kikzrKdHDfXf8VV5p
Codecov Report✅ All modified and coverable lines are covered by tests. Additional details and impacted files@@ Coverage Diff @@
## master #1724 +/- ##
=======================================
Coverage 61.59% 61.59%
=======================================
Files 84 84
Lines 21493 21493
Branches 3176 3176
=======================================
Hits 13239 13239
Misses 6078 6078
Partials 2176 2176 ☔ View full report in Codecov by Harness. 🚀 New features to boost your workflow:
|
…the no_create comment
Removing the #:stop makes no_create usable, but it leaves OMP_DATA able to
produce a directive with no clauses at all. OMP_NOCREATE_STR now returns '',
and OMP_DATA's `default` is None by default so OMP_DEFAULT_STR contributes
nothing either, so GPU_DATA(no_create='[a]') expanded to:
!$omp target data
a = 1
!$omp end target data
OpenMP requires `target data` to carry at least one map, use_device_ptr or
use_device_addr clause, so an OpenMP build got a Fortran compile error at a
generated line -- replacing the old, clear fypp message with a worse one.
Verified by expansion on NVHPC, Cray and LLVMFlang.
Emit the body alone when there are no clauses, matching what GPU_DATA's own
#else branch does when neither backend is enabled. A #:stop cannot be used
here: GPU_DATA expands both backends before #if selects one, which is the
bug this no-op exists to fix in the first place.
Also correct the justifying comment. "OMP_DEFAULT_STR already maps
present-by-default" holds only for CCE, and only when the caller passes
default='present'; in OMP_DATA `default` is None, and NVHPC/PGI and the
fallback emit defaultmap(tofrom:...), which copies rather than reuses. The
no-op is fine and now documented, but the comment promised semantics the
code does not deliver.
Generated code is byte-identical to the previous commit for every existing
call site (3 compilers x 7 source files, 29785 lines).
|
Reviewed and pushed two fixes to this branch (89c0f71) — thanks for tracking down the cross-backend abort, the diagnosis is right. Confirmed the premise: Two things the change left open: 1. A clause-less Reproduced identically on NVHPC, Cray and LLVMFlang. OpenMP requires Fixed by emitting the body alone when there are no clauses, matching what 2. The justifying comment. " Generated code is byte-identical to your commit for every existing call site (3 compilers x 7 source files, 29785 lines) — no call site in Not touched, for the record: the parallel The GPU CI failures on this PR are unrelated infrastructure — the Phoenix job was preempted ( |
OMP_NOCREATE_STR called #:stop whenever no_create was set. GPU_PARALLEL, GPU_PARALLEL_LOOP and GPU_DATA expand both the ACC and OMP directive strings at fypp time and let the compile-time #if select one, so the abort fired on OpenACC-only builds too -- making a documented parameter unusable on every backend.
OpenMP has no no_create equivalent, and OMP_DEFAULT_STR already emits a present-by-default mapping, so emitting nothing is the closest safe behavior. Document the clause as OpenACC-only, matching the existing GPU_CACHE note.
Generated Fortran is byte-identical across all 109 .fpp files in the three targets: every call site passes no_create=None, which already took the empty-string path.
Closes #1687
Claude-Session: https://claude.ai/code/session_016xc51kikzrKdHDfXf8VV5p
Description
OMP_NOCREATE_STRcalled#:stop 'no_create is not supported yet'wheneverno_createwas non-None. BecauseGPU_PARALLEL,GPU_PARALLEL_LOOPandGPU_DATAbuild both the ACC and OMP directive strings with#:setand then let the compile-time#if defined(MFC_OpenACC)/#elif defined(MFC_OpenMP)pick one, that#:stopfired during fypp preprocessing on OpenACC-only builds too — making a documented public parameter unusable on every backend, with an error pointing intoomp_macros.fpprather than at the caller.This takes option (1) from the issue: the OpenMP path becomes a documented no-op, and the working OpenACC implementation (
GEN_NOCREATE_STR) stays reachable.Worth noting for context:
MFC_OpenACC/MFC_OpenMPare never passed to fypp —cmake/Fypp.cmakeonly definesMFC_<CompilerId>,MFC_<TARGET>,MFC_COMPILER,MFC_CASE_OPTIMIZATIONandchemistry. So fypp cannot know which backend will survive, and expanding both is structural rather than incidental. The invariant that follows is that every clause helper must be evaluable for every build; a#:stopin one backend's helper is an unconditional abort, not a guard.Emitting nothing is the closest safe behavior rather than a silent wrong answer: OpenACC's
no_createasks for "use the device copy if present, otherwise the host copy, don't allocate", andOMP_DEFAULT_STRalready emitsdefaultmap(present:allocatable)(Cray) /defaultmap(tofrom:...)— the present-by-default behavior is already ambient.Also adds
(OpenACC only)to theno_createrow of the three parameter tables ingpuParallelization.md, matching the existingGPU_CACHEconvention ("NOTE Does not do anything for OpenMP currently"). Without it, the fix trades a loud failure for a silent one.The replacement comment is deliberately the same line count as the code it replaces, so fypp's
# linemarkers don't shift and the generated Fortran stays byte-identical (see Testing).Closes #1687.
Type of change (delete unused ones)
Testing
MFC_SIMULATIONonly, no OpenMP anywhere:no_create='[a]'on each):Macro OpenACC OpenMP
GPU_PARALLEL!$acc parallel default(present) no_create(a)!$omp target teams defaultmap(tofrom:aggregate) …GPU_DATA!$acc data no_create(a)!$omp target dataGPU_PARALLEL_LOOP!$acc parallel loop gang vector default(present) private(i) no_create(a)!$omp target teams loop … private(i).fppin the tree twice (original vs. patchedomp_macros.fpp), using each target's real generated includes and the exact flag set fromcmake/Fypp.cmake, and diffed the generated Fortran:Target Files Result
pre_process29 byte-identicalsimulation57 byte-identicalpost_process23 byte-identicalAlso repeated for
chemistry=Trueand for--case-optimization+chemistry=True— byte-identical in every configuration.(Only fypp's embedded absolute source path differs between the two checkouts; normalized away.) Expected, since every call site passes
no_create=Noneand already took the#:set no_create_val = ''path — but demonstrated rather than asserted../mfc.sh format— 294 files unchanged./mfc.sh precheck— 7/7 passed./mfc.sh build—pre_process,simulation,post_processall build./mfc.sh test— 609/611 pass. Two chemistry cases failed:2D -> Chemistry -> Reacting Mixing Layer(C4EB58A8, tolerance) and2D -> Chemistry -> Spatial Reacting Mixing Layer(56F8C4BC,pre_processexit 1). I don't believe these are mine, and I checked rather than assumed: both pass when run in isolation with this patch applied, and both pass on stock master. Point 3's expansion diff also holds for their exact build configuration — byte-identical underchemistry=True(29 + 57 files) and under--case-optimization+chemistry=True(39 files) — so the binaries under test are unchanged by this patch. 56F8C4BC's error ishcid=274 file has more lines than the grid: examples/2D_spatial_reacting_mixing_layer/IC/prim.1.00.000000.dat, i.e. a shared example input read against the harness's shrunken 31×31 grid, which reads like interference in the parallel full-suite run. Caveat: I did not re-run the full 41-minute suite on master to reproduce them there, so I'm flagging rather than claiming a known flake — happy to dig further if you'd like.I have no GPU or ACC-capable compiler, so the emitted
no_create(...)syntax has not been compiled by an OpenACC compiler — though it is the sameGEN_PARENTHESES_CLAUSEoutput as every other ACC clause here, and nothing in the tree passesno_createat runtime today.No test added.
toolchain/mfc/test/cases.pygenerates end-to-end solver runs compared against golden files; there is no unit layer for macro expansion, and ano_createcase would require inventing a solver call site that passes the parameter. Happy to add a fypp-expansion smoke test as new infrastructure if you'd like it, but that felt like its own PR.Checklist
Check these like this
[x]to indicate which of the below applies.See the developer guide for full coding standards.
GPU changes (expand if you modified
src/simulation/)Audit of the other clauses (per the issue's closing question)
You asked whether
create,attach,deviceptrandpresentshare the same trap. I checked every#:stopin the macro layer:createOMP_CREATE_STR→map(always,alloc:)presentOMP_PRESENT_STR→map(present,alloc:)deviceptrOMP_DEVICEPTR_STR→use_device_ptr(...)attachOMP_PARALLEL*default='none'OMP_DEFAULT_STR(omp_macros.fpp:36)defaultis public and documented as accepting'present'or'none';GEN_DEFAULT_STRhandles'none'correctly butOMP_DEFAULT_STR#:stops on it, soGPU_PARALLEL_LOOP(default='none')aborts fypp on an OpenACC-only build for exactly the same reason.no_create, emitting nothing fordefault='none'would be a semantic change rather than a no-op —default(none)demands explicit data clauses, and silently dropping it would weaken a correctness check the caller asked for. Happy to open a separate issue, or to fold a fix in here if you'd prefer.#:stops (shared_parallel_macros.fpp:32,34,92,omp_macros.fpp:262,319) all reject malformed input — unbalanced parentheses, a reduction list without an operator, aGPU_DATAwrapping no code. Those are backend-independent and correct as-is.AI code reviews
Reviews are not retriggered automatically. To request a review, comment on the PR:
@claude full review— Claude full review (also triggers on PR open/reopen/ready)claude-full-review— Claude full review via label