3.5 KiB
§116 — Optimization level is a property of the FILE, not the function: read a family 0/N against the member's stub HOME (Phase 29 T79)
family_sweep --hseq templates the exemplar's C into each member's stub file. -O0-ness is applied
by the Makefile per object (WHALE_O0B_OBJS, O0_CLUSTER_OBJS, build/src/boot.o, …), so a
family whose exemplar was matched at -O0 banks only where the member's stub happens to live in an
-O0 object too. Nothing in the sweep, the remap, or the byte-gate reports the mismatch: the draft
compiles fine, and the gate correctly rejects 137 subtly-wrong bodies.
0x801457a4 swept 0/137 on exactly this. In ov_SC01_077 the definition sits in
ov_SC01_077_o0b.c (the whale -O0 object); in all 137 other overlays the same function's stub sits
in <ov>_after.c, which is -O2. Same C, same remap, wrong flag.
The tell, before spending a sweep: find the exemplar's home file and ask whether the Makefile
gives that object a non-default CC1FLAGS. If it does, check where the members' stubs live. This is
the same class as the Phase-29 Task-1 swing verdict (0x8013c964/0x8013c938 compiled -O2 by the
sweep and masked-MATCHing only at -O0) — that one was diagnosed at the compile-flag level; this
one shows the flag is really a file-placement question.
The fix moves the DEFINITION, not the stub — and here is why the obvious shortcut fails
A carved -O0 object whose .text ends exactly at the target function's vram can absorb that
function by appending it, so the linker places it at the same address either way. That makes
"just move the member's INCLUDE_ASM(...) line into the -O0 file" look byte-neutral by
construction. It is not even buildable, and the reason is splat, not the linker:
INCLUDE_ASM("asm/<ov>/nonmatchings/<ov>_after", func_X)resolves to a.sfile that splat only emits whilefunc_XisINCLUDE_ASM'd in that segment's own.c. Delete the line from<ov>_after.cand the nextmake extractstops generatingasm/<ov>/nonmatchings/<ov>_after/func_X.s— so the relocated reference in<ov>_o0b.cfails assembly withcan't open … func_X.s. Verified across all 133 overlays at once (Phase 29 T80).
asm/ layout follows the segment; object membership follows the .c file. Moving a stub
line changes the second while silently invalidating the first. ov_SC01_077 gets away with the
_o0b placement only because it holds a real definition there — nothing references a .s.
So the rollout is: stage the remapped body into <ov>_o0b.c and drop the INCLUDE_ASM from
<ov>_after.c in the same edit, then gate. That is a two-file atomic substitution, which
harvest_verify/family_sweep do not do (they substitute a draft for the stub in the stub's own
file), so this class needs its own small driver. Still prefer it over a splat re-carve — a re-carve
is the Arm-A wall (+0x20 data-symbol shift on 3 of 4 sampled overlays).
The law: a family-wide
0/Nwhose exemplar lives in a flag-overridden object is a build-graph statement, not a codegen one. Check the object's flags and the members' stub homes before routing it to the permuter or logging it as intrinsic.The corollary, learned the hard way: "byte-neutral by construction" is a claim about the linker. The build graph has other stages, and splat's asm generation is keyed to a different partition (segment) than the one you are editing (object). Build it before you call it neutral.