From b1edca0b8fc17abcef933fe15a247e5e29a3abf8 Mon Sep 17 00:00:00 2001 From: Spencer Bryngelson Date: Wed, 13 May 2026 09:17:22 -0500 Subject: [PATCH 1/2] fix: patch fypp to emit resync linemarker after single-line $: calls Single-line $:GPU_PARALLEL_LOOP() and similar macros expand to leaving the next Fortran statement attributed to the macro call-site line rather than the following source line. This causes off-by-1 errors in all backtraces, compiler error messages, and debugger line info for every GPU-macro-wrapped loop body in the codebase (~2188 affected call sites). Root cause: fypp's _postprocess_eval_line only emits a trailing resync linemarker when the $: call spans >1 source lines (multiline) or when line-folding splits output (unsync). Single-line calls that produce multi-line output hit neither condition. Fix: always emit the resync marker after any $: call that ends its line. Implemented as a patch applied to the installed fypp.py after venv setup in toolchain/bootstrap/python.sh, with a sentinel check so it is idempotent across reinstalls. --- src/common/include/2dHardcodedIC.fpp | 4 +-- toolchain/bootstrap/python.sh | 17 +++++++++++++ .../patches/fypp-linemarker-resync.patch | 25 +++++++++++++++++++ 3 files changed, 44 insertions(+), 2 deletions(-) create mode 100644 toolchain/patches/fypp-linemarker-resync.patch diff --git a/src/common/include/2dHardcodedIC.fpp b/src/common/include/2dHardcodedIC.fpp index d6c3fed97f..7aae7721c0 100644 --- a/src/common/include/2dHardcodedIC.fpp +++ b/src/common/include/2dHardcodedIC.fpp @@ -292,10 +292,10 @@ & - patch_icpp(1)%x_centroid)**2.0 - (y_cc(j) - patch_icpp(1)%y_centroid)**2.0)))**1.4 q_prim_vf(eqn_idx%mom%beg + 0)%sf(i, j, & & 0) = patch_icpp(1)%vel(1) + (y_cc(j) - patch_icpp(1)%y_centroid)*(5.0/(2.0*pi))*exp(1.0*(1.0 - (x_cc(i) & - & - patch_icpp(1) %x_centroid)**2.0 - (y_cc(j) - patch_icpp(1)%y_centroid)**2.0)) + & - patch_icpp(1)%x_centroid)**2.0 - (y_cc(j) - patch_icpp(1)%y_centroid)**2.0)) q_prim_vf(eqn_idx%mom%beg + 1)%sf(i, j, & & 0) = patch_icpp(1)%vel(2) - (x_cc(i) - patch_icpp(1)%x_centroid)*(5.0/(2.0*pi))*exp(1.0*(1.0 - (x_cc(i) & - & - patch_icpp(1) %x_centroid)**2.0 - (y_cc(j) - patch_icpp(1)%y_centroid)**2.0)) + & - patch_icpp(1)%x_centroid)**2.0 - (y_cc(j) - patch_icpp(1)%y_centroid)**2.0)) end if case (281) ! Acoustic pulse ! This is patch is hard-coded for test suite optimization used in the 2D_acoustic_pulse case: This analytic patch uses diff --git a/toolchain/bootstrap/python.sh b/toolchain/bootstrap/python.sh index ddbdb94749..cb33162886 100644 --- a/toolchain/bootstrap/python.sh +++ b/toolchain/bootstrap/python.sh @@ -408,3 +408,20 @@ if ! cmp "$(pwd)/toolchain/pyproject.toml" "$(pwd)/build/pyproject.toml" > /dev/ fi # end of USE_UV=0 (pip) block fi + + +# Apply patches to installed packages. +# fypp: always emit a resync linemarker after single-line $: macro calls so +# that the compiler attributes the following Fortran statement to the correct +# source line rather than the call-site line (off-by-1 in backtraces). +FYPP_PY="$(python3 -c "import fypp; print(fypp.__file__)" 2>/dev/null)" +FYPP_PATCH="$(pwd)/toolchain/patches/fypp-linemarker-resync.patch" +if [ -n "$FYPP_PY" ] && [ -f "$FYPP_PATCH" ]; then + if ! grep -q "or True" "$FYPP_PY" 2>/dev/null; then + if patch -p1 --forward --silent "$FYPP_PY" < "$FYPP_PATCH" 2>/dev/null; then + ok "(venv) Applied$MAGENTA fypp$COLOR_RESET linemarker-resync patch." + else + warn "(venv) Failed to apply$MAGENTA fypp$COLOR_RESET linemarker-resync patch (fypp version may have changed)." + fi + fi +fi diff --git a/toolchain/patches/fypp-linemarker-resync.patch b/toolchain/patches/fypp-linemarker-resync.patch new file mode 100644 index 0000000000..6f6dfadf7f --- /dev/null +++ b/toolchain/patches/fypp-linemarker-resync.patch @@ -0,0 +1,25 @@ +--- a/fypp.py ++++ b/fypp.py +@@ -1842,11 +1842,16 @@ class _Renderer: + if self._linenums: + # Last line was folded, but no linenums were generated for + # the continuation lines -> current line position is not + # in sync with the one calculated from the last line number + unsync = ( + len(foldedlines) and len(foldedlines[-1]) > 1 + and not self._contlinenums) + # Eval directive in source consists of more than one line + multiline = span[1] - span[0] > 1 +- if unsync or multiline: ++ # Always emit a resync marker after a $: call. Without this, ++ # single-line $: calls that expand to multi-line #if/#endif ++ # blocks (e.g. GPU_PARALLEL_LOOP) cause the compiler to ++ # attribute the next Fortran statement to the call-site line ++ # rather than the following source line, producing off-by-1 ++ # errors in backtraces and debugger line info. ++ if unsync or multiline or True: + # For inline eval directives span[0] == span[1] + # -> next line is span[0] + 1 and not span[1] as for + # line eval directives + nextline = max(span[1], span[0] + 1) + trailing += self._linenumdir(nextline, fname) From 1c83fedb63fd95418900b4db5971b9c5ed7b21bd Mon Sep 17 00:00:00 2001 From: Spencer Bryngelson Date: Wed, 13 May 2026 12:44:45 -0500 Subject: [PATCH 2/2] fix: use patch comment as idempotency sentinel in python.sh --- toolchain/bootstrap/python.sh | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/toolchain/bootstrap/python.sh b/toolchain/bootstrap/python.sh index cb33162886..2809918b76 100644 --- a/toolchain/bootstrap/python.sh +++ b/toolchain/bootstrap/python.sh @@ -417,7 +417,7 @@ fi FYPP_PY="$(python3 -c "import fypp; print(fypp.__file__)" 2>/dev/null)" FYPP_PATCH="$(pwd)/toolchain/patches/fypp-linemarker-resync.patch" if [ -n "$FYPP_PY" ] && [ -f "$FYPP_PATCH" ]; then - if ! grep -q "or True" "$FYPP_PY" 2>/dev/null; then + if ! grep -q "Always emit a resync marker" "$FYPP_PY" 2>/dev/null; then if patch -p1 --forward --silent "$FYPP_PY" < "$FYPP_PATCH" 2>/dev/null; then ok "(venv) Applied$MAGENTA fypp$COLOR_RESET linemarker-resync patch." else