cgen: str N_INDEX read -> 3-word {ptr,len,cap} -- Phase 2 F2 (both stages)

str element value read at N_INDEX dropped the cap word (2-word ptr,len load); str is 24B {ptr,len,cap} since 1140a59. A new named helper cgslicehdr (both stages) loads the full 3-word header and is called by the N_INDEX str-element sites, kind-gated type_isstr/elemisstr -- never size==24, since str and slice collide at 24B. The base-targeting word loads last (clobber-safe). cstage==wwstage byte-identical. The #9 typeassert leaf is split out to F2b (it needs a wwstage spill twin first).

test/wcc/932: table-driven runtime .cap-survives probe over both N_INDEX base forms and both drivers; verified fail-before/pass-after. NNN<950 mirrors the 928 precedent -- the fixtures are self-contained (/tmp, no imports), so rule-14's selfhost-sibling race does not apply.

main.combined.ww regenerated via the canonical make path (md5-stable) and committed alongside source, per the 1140a59 precedent.
This commit is contained in:
2026-05-24 12:27:15 +09:00
parent fb4c567e0d
commit 97707155ae
7 changed files with 318 additions and 53 deletions

View File

@@ -747,6 +747,16 @@ fn emitdispreg(off: i64, reg: str) void = {
emitline(")");
};
// emitmovqload — `MOVQ off(base), dst`, the per-word unit of a
// 3-word slice/str header load (cgslicehdr).
fn emitmovqload(off: i64, base: str, dst: str) void = {
emitline("\tMOVQ\t");
emitdispreg(off, base);
emitline(", ");
emitline(dst);
emitline("\n");
};
// emitoff — print an integer offset, suppressing it entirely when 0.
// Use before any emitline("(BP)...") or emitline("(SB)...") sequence.
// Plan 9 cc convention: "(BP)" not "0(BP)".