You signed in with another tab or window. Reload to refresh your session.You signed out in another tab or window. Reload to refresh your session.You switched accounts on another tab or window. Reload to refresh your session.Dismiss alert
Found while scoping VCR-RA-002 (#428). The optimized (non-relocatable) codegen path emits an exported leaf function that uses callee-saved registers r4-r8 as scratch and returns via bx lr with no push/pop — so an AAPCS caller's r4-r8 are corrupted across the call.
synth compile leaf3.wat -o /tmp/leaf3.elf -b arm --target cortex-m4 --all-exports
arm-none-eabi-objdump -d -M force-thumb /tmp/leaf3.elf # see <leaf3>
Output (abridged) — leaf3 is a global symbol:
leaf3:
movs r7,#1 ; add.w r8,r0,r7 ; mov r4,r8 ; ... uses r4,r5,r6,r7,r8 ...
mov r0,ip
bx lr <-- no push {r4-r8,lr} / pop {..,pc}
Scope / what it is NOT
Independent of recent levers: reproduces with SYNTH_NO_LOCAL_PROMOTE=1 and with SYNTH_RANGE_REALLOC=0 (realloc+shrink disabled), so shrink_callee_saved_saves is not the cause — the non-relocatable path itself omits the callee-saved preservation.
The --relocatable build of the same function is correct: it emits stmdb sp!, {r4,r5,r6,r7,r8,lr} / ldmia sp!, {..,pc}. So only the optimized/non-relocatable path is affected.
Is the non-relocatable path a whole-program/self-contained model where synth controls every caller and exported entry points are only reached from the vector table / runtime that doesn't rely on r4-r8 preservation? If so this is benign by construction and should be documented as such.
If exported functions can be reached by external AAPCS code (host-link / native-pointer ABI), this corrupts caller state and needs the prologue restored.
Contrast: a non-leaf (with a call) on this same path reportedly doespush {r4-r8,lr} — what determines the push, and why is the leaf case skipped?
Filing for investigation, not asserting a fix — needs (1) resolved first.
— issue-hunt loop (avrabe automation), not a maintainer decision.
Found while scoping VCR-RA-002 (#428). The optimized (non-relocatable) codegen path emits an exported leaf function that uses callee-saved registers r4-r8 as scratch and returns via
bx lrwith nopush/pop— so an AAPCS caller's r4-r8 are corrupted across the call.Repro (generic fixture)
Output (abridged) —
leaf3is a global symbol:Scope / what it is NOT
SYNTH_NO_LOCAL_PROMOTE=1and withSYNTH_RANGE_REALLOC=0(realloc+shrink disabled), soshrink_callee_saved_savesis not the cause — the non-relocatable path itself omits the callee-saved preservation.--relocatablebuild of the same function is correct: it emitsstmdb sp!, {r4,r5,r6,r7,r8,lr}/ldmia sp!, {..,pc}. So only the optimized/non-relocatable path is affected.*_differential.pychecks compare the callee's result, not the caller's clobbered r4-r8, so they pass. This is the arm regalloc: select_with_stack allocates param registers (r0-r3) for temps/results before live param reads — i64_lowering fuzz class #193/v0.11.21 RISC-V backend: clobbers callee-saved s-registers (s1–s6) with no prologue/epilogue — ABI violation, corrupts caller #220 latent class.Open questions (confirm before fixing)
push {r4-r8,lr}— what determines the push, and why is the leaf case skipped?Filing for investigation, not asserting a fix — needs (1) resolved first.
— issue-hunt loop (avrabe automation), not a maintainer decision.