From 873f4883a5bd10d42ac698cfa99587d72d0d4090 Mon Sep 17 00:00:00 2001 From: Spencer Bryngelson Date: Sun, 26 Jul 2026 22:34:56 -0400 Subject: [PATCH 1/9] fix: honor cray_inline/cray_noinline on Cray GPU builds and use INLINENEVER --- src/common/include/parallel_macros.fpp | 49 +++++++------------------- 1 file changed, 12 insertions(+), 37 deletions(-) diff --git a/src/common/include/parallel_macros.fpp b/src/common/include/parallel_macros.fpp index b1382ec49a..5a606ba342 100644 --- a/src/common/include/parallel_macros.fpp +++ b/src/common/include/parallel_macros.fpp @@ -63,51 +63,26 @@ & extraAccArgs=extraAccArgs) #:set omp_directive = OMP_ROUTINE(function_name=function_name, nohost=nohost, extraOmpArgs=extraOmpArgs) - #:if cray_noinline == True + #! The caller asks for a Cray inlining decision per routine, so honour it on every + #! Cray build — CPU and GPU alike. The !DIR$ line is a Cray-only directive, and it + #! accompanies the offload directive rather than replacing it. Note the named + #! never-inline directive is INLINENEVER; !DIR$ NOINLINE is a separate, nameless, + #! call-site directive that ftn rejects when given a routine name (ftn-790). + #:if cray_inline or cray_noinline #:if not isinstance(function_name, str) - #:stop "When using cray_noinline, function name must be given and given as a string" + #:stop "When using cray_inline/cray_noinline, function name must be given and given as a string" #:endif - #:set cray_noinline_directive = ('!DIR$ NOINLINE ' + function_name).strip('\n') + #:set cray_keyword = 'INLINEALWAYS' if cray_inline else 'INLINENEVER' + #:set cray_directive = ('!DIR$ ' + cray_keyword + ' ' + function_name).strip('\n') #ifdef _CRAYFTN -#if MFC_OpenACC - $:acc_directive -#elif MFC_OpenMP - $:omp_directive -#else - $:cray_noinline_directive -#endif - #! On non-Cray CPU builds (no _CRAYFTN, no MFC_OpenACC, no MFC_OpenMP), nothing is - #! emitted — intentional, since !DIR$ NOINLINE is a Cray-specific directive. -#elif MFC_OpenACC - $:acc_directive -#elif MFC_OpenMP - $:omp_directive -#endif - #:elif cray_inline == True - #:if not isinstance(function_name, str) - #:stop "When inlining for Cray Compiler, function name must be given and given as a string" - #:endif - #:set cray_directive = ('!DIR$ INLINEALWAYS ' + function_name).strip('\n') -#ifdef _CRAYFTN -#if MFC_OpenACC - $:acc_directive -#elif MFC_OpenMP - $:omp_directive -#else $:cray_directive #endif -#elif MFC_OpenACC - $:acc_directive -#elif MFC_OpenMP - $:omp_directive -#endif - #:else + #:endif #if MFC_OpenACC - $:acc_directive + $:acc_directive #elif MFC_OpenMP - $:omp_directive + $:omp_directive #endif - #:endif #:enddef ! Declare device-resident data From e6645f9eb2f0a49ccd0c0352ddc4523be4b3f7ca Mon Sep 17 00:00:00 2001 From: Spencer Bryngelson Date: Mon, 27 Jul 2026 08:58:05 -0400 Subject: [PATCH 2/9] build: move Frontier to CCE 21.0.2 and ROCm 7.2.0, working around AGPR pass crash --- toolchain/modules | 13 +++++++++++-- 1 file changed, 11 insertions(+), 2 deletions(-) diff --git a/toolchain/modules b/toolchain/modules index 168cb37444..c7c3dd320a 100644 --- a/toolchain/modules +++ b/toolchain/modules @@ -49,9 +49,18 @@ pifx-cpu MPICC=mpiicc MPICXX=mpiicpc MPIFC=mpiifort pifx-cpu I_MPI_CC=icx I_MPI_CXX=icpx I_MPI_F90=ifx I_MPI_F77=ifx f OLCF Frontier -f-all cpe/25.03 rocm/6.3.1 +# cpe/26.03 defaults to cce/21.0.0; pin 21.0.2. rocprofiler-compute is not listed: +# its modulefile reloads darshan-runtime, which cpe/26.03 deactivates, and rocm/7 +# already provides rocprof, rocprof-compute, and rocprofv3. +f-all cpe/26.03 cce/21.0.2 rocm/7.2.0 f-all cray-fftw cray-hdf5 python cmake -f-gpu python craype-accel-amd-gfx90a rocprofiler-compute/3.0.0 +f-gpu craype-accel-amd-gfx90a +# CCE 21 aborts linking simulation in the AMDGPU "Rewrite AGPR-Copy-MFMA" pass +# (SlotIndexes.h "Attempt to compare reserved index") on the s_compute_bubble_EE_source +# kernel. The pass runs even though every gfx90a function CCE emits carries +# amdgpu-agpr-alloc="0" and MFC contains no v_mfma instructions, so dropping the MAI +# subtarget feature makes it bail out with no effect on generated code. +f-gpu CRAY_CCE_LLD_ARGS=-plugin-opt=-mattr=-mai-insts famd OLCF Frontier AMD famd-all python cmake From c2e54d70a2aeec150a8261f9d4c52576e81a1388 Mon Sep 17 00:00:00 2001 From: Spencer Bryngelson Date: Mon, 27 Jul 2026 22:07:19 -0400 Subject: [PATCH 3/9] fix: pass IBM pb/mv unconditionally instead of as optional args CCE 21 dereferences the null dope vector an absent optional array presents to the OpenACC data environment, segfaulting s_ibm_correct_state. pb_ts/mv_ts are always allocated (zero-sized when unused), so pass them unconditionally and drop the optional attribute. No present() guards existed in m_ibm, so this is logic-neutral. --- src/simulation/m_ibm.fpp | 2 +- src/simulation/m_time_steppers.fpp | 9 ++++----- 2 files changed, 5 insertions(+), 6 deletions(-) diff --git a/src/simulation/m_ibm.fpp b/src/simulation/m_ibm.fpp index d2e598ed22..0955f92dd3 100644 --- a/src/simulation/m_ibm.fpp +++ b/src/simulation/m_ibm.fpp @@ -144,7 +144,7 @@ contains type(scalar_field), dimension(sys_size), intent(inout) :: q_cons_vf !< Primitive Variables type(scalar_field), dimension(sys_size), intent(inout) :: q_prim_vf !< Primitive Variables - real(stp), dimension(idwbuff(1)%beg:,idwbuff(2)%beg:,idwbuff(3)%beg:,1:,1:), optional, intent(inout) :: pb_in, mv_in + real(stp), dimension(idwbuff(1)%beg:,idwbuff(2)%beg:,idwbuff(3)%beg:,1:,1:), intent(inout) :: pb_in, mv_in integer :: i, j, k, l, q, r !< Iterator variables integer :: patch_id, patch_id_temp !< Patch ID of ghost point real(wp) :: rho, gamma, pi_inf, dyn_pres !< Mixture variables diff --git a/src/simulation/m_time_steppers.fpp b/src/simulation/m_time_steppers.fpp index daf1c2a734..ab6c63a999 100644 --- a/src/simulation/m_time_steppers.fpp +++ b/src/simulation/m_time_steppers.fpp @@ -550,11 +550,10 @@ contains end if ! update the ghost fluid properties point values based on IB state - if (qbmm .and. .not. polytropic) then - call s_ibm_correct_state(q_cons_ts(1)%vf, q_prim_vf, pb_ts(1)%sf, mv_ts(1)%sf) - else - call s_ibm_correct_state(q_cons_ts(1)%vf, q_prim_vf) - end if + ! pb_ts/mv_ts are always allocated (zero-sized when unused), so pass + ! them unconditionally: an absent optional array reaches the OpenACC + ! data environment as a null dope vector, which CCE 21 dereferences. + call s_ibm_correct_state(q_cons_ts(1)%vf, q_prim_vf, pb_ts(1)%sf, mv_ts(1)%sf) end if ! Grind: minimum wall-clock time of a full RK stage (compute + halo H2D/D2H + From 17408d791cd0c8fd985b8cf4acb277fe36246943 Mon Sep 17 00:00:00 2001 From: Spencer Bryngelson Date: Mon, 27 Jul 2026 22:08:26 -0400 Subject: [PATCH 4/9] fix: avoid CCE 21 dropping dynamically-indexed private-array stores AMDGPUPromoteAllocaToVector silently discards a store to arr(v) when arr is 1-based and v is a runtime value. CCE 21 canonicalizes the element index as v + 0x3FFFFFFF, harmless in wrapping address arithmetic but not once the array is registerized and the index becomes an equality comparison, so every test misses and the store vanishes. Here idx(norm_dir) = idx(norm_dir) + 1 never executed and the viscous flux averaged the gradient at cell j instead of j+1. Write the constant index explicitly instead. --- src/simulation/m_riemann_solver_lf.fpp | 8 +++++++- src/simulation/m_riemann_state.fpp | 16 ++++++++++++++-- 2 files changed, 21 insertions(+), 3 deletions(-) diff --git a/src/simulation/m_riemann_solver_lf.fpp b/src/simulation/m_riemann_solver_lf.fpp index 512a576e71..5185d5e737 100644 --- a/src/simulation/m_riemann_solver_lf.fpp +++ b/src/simulation/m_riemann_solver_lf.fpp @@ -505,7 +505,13 @@ contains idx_right_phys(1) = j idx_right_phys(2) = k idx_right_phys(3) = l - idx_right_phys(norm_dir) = idx_right_phys(norm_dir) + 1 + if (norm_dir == 1) then + idx_right_phys(1) = j + 1 + else if (norm_dir == 2) then + idx_right_phys(2) = k + 1 + else + idx_right_phys(3) = l + 1 + end if if (norm_dir == 1) then $:GPU_LOOP(parallelism='[seq]') diff --git a/src/simulation/m_riemann_state.fpp b/src/simulation/m_riemann_state.fpp index 5fe5499c04..04f97e4798 100644 --- a/src/simulation/m_riemann_state.fpp +++ b/src/simulation/m_riemann_state.fpp @@ -613,7 +613,13 @@ contains do j = ix%beg, ix%end ! Determine indices for the 'right' state for averaging across the interface idx_rp = [j, k, l] - idx_rp(norm_dir) = idx_rp(norm_dir) + 1 + if (norm_dir == 1) then + idx_rp(1) = j + 1 + else if (norm_dir == 2) then + idx_rp(2) = k + 1 + else + idx_rp(3) = l + 1 + end if ! Average velocities and their derivatives at the interface For cylindrical: x-dir ~ axial (z_cyl), y-dir ~ ! radial (r_cyl), z-dir ~ azimuthal (theta_cyl) @@ -828,7 +834,13 @@ contains idx_right_phys(1) = j_loop idx_right_phys(2) = k_loop idx_right_phys(3) = l_loop - idx_right_phys(norm_dir) = idx_right_phys(norm_dir) + 1 + if (norm_dir == 1) then + idx_right_phys(1) = j_loop + 1 + else if (norm_dir == 2) then + idx_right_phys(2) = k_loop + 1 + else + idx_right_phys(3) = l_loop + 1 + end if vel_grad_avg = 0.0_wp do vel_comp_idx = 1, num_dims From 9350965973e6afecbb0b98a360c71ee93b50994f Mon Sep 17 00:00:00 2001 From: Spencer Bryngelson Date: Mon, 27 Jul 2026 22:09:38 -0400 Subject: [PATCH 5/9] fix: keep Y_rs off private frame offset 0 in s_compute_pressure ftn builds a flat pointer to a private object as zext(offset) with no aperture. The flat->private cast back is select(p == null, ~0, trunc p), so an object at frame offset 0 yields 0xFFFFFFFF and the scratch store lands 4 GiB out of bounds, faulting every chemistry case on CCE 21. A lower bound of 0 as an unused pad keeps Y_rs(1) off offset 0. --- src/common/m_variables_conversion.fpp | 21 +++++++++++++-------- 1 file changed, 13 insertions(+), 8 deletions(-) diff --git a/src/common/m_variables_conversion.fpp b/src/common/m_variables_conversion.fpp index a230416b5e..4302075a55 100644 --- a/src/common/m_variables_conversion.fpp +++ b/src/common/m_variables_conversion.fpp @@ -94,11 +94,16 @@ contains ! Chemistry real(wp), dimension(1:num_species), intent(in) :: rhoYks - real(wp), dimension(1:num_species) :: Y_rs - real(wp) :: E_e - real(wp) :: e_Per_Kg, Pdyn_Per_Kg - real(wp) :: T_guess - integer :: s !< Generic loop iterator + !> Lower bound 0 is a deliberate, unused pad element: it keeps Y_rs(1) off private frame offset 0. Cray ftn builds a flat + !! pointer to a private object as zext(offset) with no aperture, so the flat->private cast back (select(p == null, ~0, trunc + !! p)) turns offset 0 into 0xFFFFFFFF and the scratch store lands 4 GiB out of bounds. Faults every chemistry case on CCE + !! 21/gfx90a. Do not tighten to 1:num_species without re-checking that the device image is free of `s_cselect_b32 sN, 0, + !! -1`. + real(wp), dimension(0:num_species) :: Y_rs + real(wp) :: E_e + real(wp) :: e_Per_Kg, Pdyn_Per_Kg + real(wp) :: T_guess + integer :: s !< Generic loop iterator #:if not chemistry ! Depending on model_eqns and bubbles_euler, the appropriate procedure for computing pressure is targeted by the ! procedure pointer @@ -134,14 +139,14 @@ contains end if #:else ! Reacting mixture pressure from temperature and species - Y_rs(:) = rhoYks(:)/rho + Y_rs(1:num_species) = rhoYks(:)/rho e_Per_Kg = energy/rho Pdyn_Per_Kg = dyn_p/rho T_guess = T - call get_temperature(e_Per_Kg - Pdyn_Per_Kg, T_guess, Y_rs, .true., T) - call get_pressure(rho, T, Y_rs, pres) + call get_temperature(e_Per_Kg - Pdyn_Per_Kg, T_guess, Y_rs(1:num_species), .true., T) + call get_pressure(rho, T, Y_rs(1:num_species), pres) #:endif end subroutine s_compute_pressure From 41dae3c33a5b5594b85786bf155b744c2f88e2fd Mon Sep 17 00:00:00 2001 From: Spencer Bryngelson Date: Mon, 27 Jul 2026 22:10:20 -0400 Subject: [PATCH 6/9] build: base dependency and configure skips on real state, not CMakeCache.txt is_configured() only checked for CMakeCache.txt, which CMake writes before it generates the build system. A configure interrupted in between made MFC skip configure and fail with 'No rule to make target Makefile'; a dependency build that crashed made MFC skip that dependency forever, leaving CMAKE_PREFIX_PATH pointing at an empty install tree and surfacing as a confusing find_package error elsewhere. Require the generator's build file, and gate the dependency skip on install_manifest.txt, which CMake writes only after a successful install. --- toolchain/mfc/build.py | 28 +++++++++++++++++++++------- 1 file changed, 21 insertions(+), 7 deletions(-) diff --git a/toolchain/mfc/build.py b/toolchain/mfc/build.py index 60cfc1e3ea..68891498fd 100644 --- a/toolchain/mfc/build.py +++ b/toolchain/mfc/build.py @@ -367,9 +367,21 @@ def get_install_binpath(self, case: Case) -> str: return os.sep.join([self.get_install_dirpath(case), "bin", self.name]) def is_configured(self, case: Case) -> bool: - # We assume that if the CMakeCache.txt file exists, then the target is - # configured. (this isn't perfect, but it's good enough for now) - return os.path.isfile(os.sep.join([self.get_staging_dirpath(case), "CMakeCache.txt"])) + # CMake writes CMakeCache.txt before it generates the build system, so the + # cache alone does not mean the target is ready to build: a configure that + # was interrupted leaves the cache behind with no Makefile, and skipping + # configure on that basis fails later with "No rule to make target". + # Require the generator's build file too. + staging_dirpath = self.get_staging_dirpath(case) + if not os.path.isfile(os.sep.join([staging_dirpath, "CMakeCache.txt"])): + return False + + return any(os.path.isfile(os.sep.join([staging_dirpath, f])) for f in ("build.ninja", "Makefile")) + + def is_installed(self, case: Case) -> bool: + # CMake writes install_manifest.txt only after a successful install, so + # unlike CMakeCache.txt it is not left behind by a build that crashed. + return os.path.isfile(os.sep.join([self.get_staging_dirpath(case), "install_manifest.txt"])) def get_configuration_txt(self, case: Case) -> typing.Optional[dict]: if not self.is_configured(case): @@ -593,10 +605,12 @@ def __build_target(target: typing.Union[MFCTarget, str], case: input.MFCInputFil history.add(target.name) - # Dependencies are pinned to fixed versions. If already configured - # (built & installed by a prior --deps-only step), skip entirely - # to avoid re-entering the superbuild (which may access the network). - if target.isDependency and target.is_configured(case): + # Dependencies are pinned to fixed versions, so skip one that a prior + # --deps-only step already installed, avoiding a re-entry into the superbuild + # (which may access the network). Gate on the install, not on the configure: + # a dependency build that crashed leaves CMakeCache.txt behind, and skipping + # on that would point CMAKE_PREFIX_PATH at an empty install tree forever. + if target.isDependency and target.is_installed(case): return for dep in target.requires.compute(): From 196afd46842c7fe3137a8cf13bfef25f3467b751 Mon Sep 17 00:00:00 2001 From: Spencer Bryngelson Date: Mon, 27 Jul 2026 22:10:54 -0400 Subject: [PATCH 7/9] build: add -disable-promote-alloca-to-vector to the Frontier CCE 21 link Covers the dynamically-indexed private-array stores that the source fix does not reach. The value must stay quoted: modules.sh runs eval export $line, so an unquoted multi-word value exports only the first -plugin-opt and reports the rest to stderr, which is routinely discarded. --- toolchain/modules | 23 +++++++++++++++++------ 1 file changed, 17 insertions(+), 6 deletions(-) diff --git a/toolchain/modules b/toolchain/modules index c7c3dd320a..1238faf3ab 100644 --- a/toolchain/modules +++ b/toolchain/modules @@ -55,12 +55,23 @@ f OLCF Frontier f-all cpe/26.03 cce/21.0.2 rocm/7.2.0 f-all cray-fftw cray-hdf5 python cmake f-gpu craype-accel-amd-gfx90a -# CCE 21 aborts linking simulation in the AMDGPU "Rewrite AGPR-Copy-MFMA" pass -# (SlotIndexes.h "Attempt to compare reserved index") on the s_compute_bubble_EE_source -# kernel. The pass runs even though every gfx90a function CCE emits carries -# amdgpu-agpr-alloc="0" and MFC contains no v_mfma instructions, so dropping the MAI -# subtarget feature makes it bail out with no effect on generated code. -f-gpu CRAY_CCE_LLD_ARGS=-plugin-opt=-mattr=-mai-insts +# Two CCE 21 device-codegen workarounds. Keep the value quoted: modules.sh runs +# eval "export $line", so an unquoted multi-word value exports only the first +# -plugin-opt and reports the rest to stderr, which is routinely discarded. +# +# -mattr=-mai-insts: CCE 21 aborts linking simulation in the AMDGPU +# "Rewrite AGPR-Copy-MFMA" pass (SlotIndexes.h "Attempt to compare reserved +# index") on the s_compute_bubble_EE_source kernel. Dropping the MAI subtarget +# feature makes the pass bail out. Not codegen-neutral -- it costs the AGPR half +# of the unified register file, so pressure moves into scratch. +# +# -disable-promote-alloca-to-vector: AMDGPUPromoteAllocaToVector silently DISCARDS +# a dynamically-indexed store into a 1-based local array. For arr(v) CCE 21 +# canonicalizes the element index as v + 0x3FFFFFFF, which is harmless in +# wrapping address arithmetic but not once the array is registerized and the +# index becomes an equality comparison. Wrong answers, no diagnostic. The three +# sites we found are also fixed in source; this covers the ones we have not. +f-gpu CRAY_CCE_LLD_ARGS="-plugin-opt=-mattr=-mai-insts -plugin-opt=-disable-promote-alloca-to-vector" famd OLCF Frontier AMD famd-all python cmake From c3e257c854cfda7c5676400115986e41b684dca5 Mon Sep 17 00:00:00 2001 From: Spencer Bryngelson Date: Tue, 28 Jul 2026 10:36:41 -0400 Subject: [PATCH 8/9] fix: emit no defaultmap clauses for CCE OpenMP offload On CCE 21.0.2 the presence of any defaultmap clause makes a device-resident array read as all zeros inside the target region. A 60-line reproducer with a derived-type pointer component, a derived-type allocatable component and a bare module array reads all three correctly under a bare directive and gets zero from all three once a defaultmap clause is added; each of tofrom:aggregate, present:allocatable and present:pointer reproduces it alone. Negative controls rule out negative lower bounds and named multi-level exits. This is what broke immersed boundaries under -homp: ib_markers read as empty, so the ghost-point count came back 0, the allocation was zero-length, the explicit-shape dummy mapped as 0 bytes, and the runtime handed the kernel a host pointer to store through. Dropping the clauses is also semantically free, since OpenMP 5.0 already defaults scalars to firstprivate and the AMD branch has never emitted them. Full suite on mp goes 566/627 to 622/627, all 60 aborts eliminated, with both offload paths then failing the identical five tests. --- src/common/include/omp_macros.fpp | 22 ++++++++++++++++++++-- 1 file changed, 20 insertions(+), 2 deletions(-) diff --git a/src/common/include/omp_macros.fpp b/src/common/include/omp_macros.fpp index ff3d97fe5c..9cd020ec6a 100644 --- a/src/common/include/omp_macros.fpp +++ b/src/common/include/omp_macros.fpp @@ -26,7 +26,20 @@ #:if MFC_COMPILER == NVIDIA_COMPILER_ID or MFC_COMPILER == PGI_COMPILER_ID #:set default_val = 'defaultmap(tofrom:aggregate) defaultmap(tofrom:allocatable) defaultmap(tofrom:pointer) ' #:elif MFC_COMPILER == CCE_COMPILER_ID - #:set default_val = 'defaultmap(tofrom:aggregate) defaultmap(present:allocatable) defaultmap(present:pointer) ' + #! Emit no defaultmap at all on CCE. MEASURED on 21.0.2: the presence of + #! ANY defaultmap clause makes a resident (declare target + enter data) + #! array read as ZERO inside the target region. A 60-line reproducer with + #! a pointer component, an allocatable component and a bare module array + #! reads all three correctly with a bare directive and gets 0 from all + #! three with defaultmap added -- and each of tofrom:aggregate, + #! present:allocatable and present:pointer reproduces it on its own. + #! This is what made every IBM case fail under -homp: ib_markers read as + #! empty, so the ghost-point count came back 0. + #! Related: present:aggregate was tried and reverted earlier. It aborts + #! with "find_in_present_table failed for 'length(:)'" at + #! m_ib_patches.fpp:145 -- a genuine second residency bug that the tofrom + #! default had been masking, worth fixing separately. + #:set default_val = '' #:elif MFC_COMPILER == AMD_COMPILER_ID #:set default_val = '' #:else @@ -179,7 +192,12 @@ #:if MFC_COMPILER == NVIDIA_COMPILER_ID or MFC_COMPILER == PGI_COMPILER_ID #:set omp_start_directive = '!$omp target teams loop defaultmap(firstprivate:scalar) bind(teams,parallel) ' #:elif MFC_COMPILER == CCE_COMPILER_ID - #:set omp_start_directive = '!$omp target teams distribute parallel do defaultmap(firstprivate:scalar) ' + #! No defaultmap(firstprivate:scalar) here: it only restates the OpenMP 5.0 + #! default for scalars in a target region, and CCE 21 lets it override an + #! explicit map(to:) on a scalar. A scalar that is atomically incremented to + #! hand out array slots then becomes per-thread, so every thread gets the + #! same index -- this broke every immersed-boundary case under -homp. + #:set omp_start_directive = '!$omp target teams distribute parallel do ' #:elif MFC_COMPILER == AMD_COMPILER_ID #:set omp_start_directive = '!$omp target teams distribute parallel do ' #:else From ee75cfe3362cf354f523400f7d0fc9c315789a6a Mon Sep 17 00:00:00 2001 From: Spencer Bryngelson Date: Tue, 28 Jul 2026 12:00:08 -0400 Subject: [PATCH 9/9] docs: correct the note on the present:aggregate abort The comment claimed the find_in_present_table failure at m_ib_patches.fpp:145 was a latent MFC residency bug that the tofrom default had been masking. It is not. 'length' is real(wp) :: length(3) and is explicitly listed in that loop's private() clause, so nothing should ever look for it in the present table. Measured on a 20-line standalone: an explicitly-private local array passes with a bare directive and aborts with the identical find_in_present_table error once defaultmap(present:aggregate) is added. That makes it the same compiler defect already described above, overriding an explicit private clause rather than an explicit map or present-table residency. --- src/common/include/omp_macros.fpp | 12 ++++++++---- 1 file changed, 8 insertions(+), 4 deletions(-) diff --git a/src/common/include/omp_macros.fpp b/src/common/include/omp_macros.fpp index 9cd020ec6a..b24fec59ca 100644 --- a/src/common/include/omp_macros.fpp +++ b/src/common/include/omp_macros.fpp @@ -35,10 +35,14 @@ #! present:allocatable and present:pointer reproduces it on its own. #! This is what made every IBM case fail under -homp: ib_markers read as #! empty, so the ghost-point count came back 0. - #! Related: present:aggregate was tried and reverted earlier. It aborts - #! with "find_in_present_table failed for 'length(:)'" at - #! m_ib_patches.fpp:145 -- a genuine second residency bug that the tofrom - #! default had been masking, worth fixing separately. + #! Related: present:aggregate was tried and reverted. It aborts with + #! "find_in_present_table failed for 'length(:)'" at m_ib_patches.fpp:145. + #! That is NOT an MFC residency bug -- `length` is real(wp) :: length(3), + #! explicitly listed in that loop's private() clause, so nothing should + #! ever look for it in the present table. Measured on a 20-line standalone: + #! an explicitly-private local array passes with no defaultmap and aborts + #! the same way with defaultmap(present:aggregate). Same defect as above, + #! overriding `private` instead of `map` or present-table residency. #:set default_val = '' #:elif MFC_COMPILER == AMD_COMPILER_ID #:set default_val = ''