w6c+wwstage: route sret dest to the global symbol on struct-return into a global (#220)

Assigning a >24B by-value struct-return into a GLOBAL lvalue dropped the
struct body: the sret dest was routed to a BP scratch temp and only the
8-byte return pointer was stored (`MOVQ AX, g(SB)`); the callee wrote the full
struct to the scratch, which never reached the global. A BP-relative dest
offset cannot name a global symbol. Pre-existing GATE-BLIND silent miscompile
— both stages emit the same broken store, so byte-id (990-997) stays green
while runtime is wrong — latent until the eFinal io surface put a global
`cgoutstream: memio.stream` (>24B) on the path, where it made cgen.ww's
self-built w6c_ww buffer every function body into a corrupt global (pos stayed
0) and emit prologue-only output.

Fix, both stages, byte-identical: route the sret dest pointer to the global
symbol so the callee writes the full struct through RDI straight into the
global. cstage adds cg_sret_dest_sym, mirroring the existing str/slice global
arm (skip the @sretscr scratch, emit `LEAQ masym(sym), DI`). wwstage carries
the lhs IDENT node (sretdestnode) and emits `LEAQ name(SB), DI` via emitsymname
— identical to cstage's symbol mangling, verified cs.s==ww.s on the probe and
across 990-997. #211-family (by-value struct + global/pointer), but a distinct
site: the cstage assignment-store into a global, not the wwstage call-return.

N_LET-global static-init (`let g: T = mk()` at top level) is a separate,
independently-broken path (#221) — link-fails for init-via-call, returns 0 for
constant init — not the sret-receive gap and not on the eFinal path; deferred.

test/wcc/940_global_sret_run: global assign (plus a branched callee to defeat
const-fold), through-pointer mutation (the io vtable-callback shape that
surfaced this), and local-init/assign regressions — runtime asserts on both
stages (the net, since byte-id is gate-blind here) plus cs.s==ww.s.
Discrimination confirmed by revert+rebuild: with the global arm disabled,
global_assign emits the truncated store and exits 1.
This commit is contained in:
2026-05-30 00:46:57 +09:00
parent 176904dffc
commit 1175711021
7 changed files with 446 additions and 10 deletions

View File

@@ -252,6 +252,7 @@ TESTS = $(BIN)/test_smoke $(BIN)/test_lex $(BIN)/test_parse $(BIN)/test_check \
$(BIN)/test_nested_union_widen_run \
$(BIN)/test_sret_struct_return \
$(BIN)/test_sret_struct_return_run \
$(BIN)/test_global_sret_run \
$(BIN)/test_sret_narrow_field \
$(BIN)/test_sret_narrow_field_run \
$(BIN)/test_match_slice_variant \
@@ -846,6 +847,12 @@ $(BIN)/test_sret_struct_return_run: test/wcc/925_sret_struct_return_run.c \
$(LIB)/libwwrt.a | $(BIN)
$(CC) $(CFLAGS) -o $@ $<
$(BIN)/test_global_sret_run: test/wcc/940_global_sret_run.c \
$(BIN)/ww $(BIN)/w6c $(BIN)/w6a $(BIN)/w6l \
$(BIN)/ww_ww $(BIN)/w6c_ww $(BIN)/w6a_ww $(BIN)/w6l_ww \
$(LIB)/libwwrt.a | $(BIN)
$(CC) $(CFLAGS) -o $@ $<
$(BIN)/test_sret_narrow_field: test/wcc/730_sret_narrow_field.c \
$(BIN)/w6c $(BIN)/w6c_ww | $(BIN)
$(CC) $(CFLAGS) -o $@ $<