selfhost/cmd/wcc: cgalloc str-field store + regression test

wwstage cgalloc N_STRUCTLIT branch emitted MOVQ AX,foff(BX) for every
non-float field. For a str field the cgexpr result is (AX=ptr, BX=len)
and the single MOVQ clobbered BX with the heap pointer, dropping len.
Mirror cmd/w6c/cgen.c:4184-4190: isstrtype branch routes through CX
so BX=len survives. TY_STR only — slice/tagged/fn-pair have the same
gap on both stages (task #23, parked behind Phase 2).

New test/wcc/758_cgalloc_str_field.c is table-driven (6 rows), fails
without the fix under wwstage with predicted exit codes.
This commit is contained in:
2026-05-20 16:51:32 +09:00
parent f80927201b
commit af1549d9c5
5 changed files with 272 additions and 3 deletions

View File

@@ -15984,6 +15984,19 @@ fn cgalloc(c: *cgen, n: *node) void = {
emitint(fi.foff: i64);
emitline("(BX)\n");
fi = nil;
} else { if (isstrtype(c, fi.tnode)) {
// alloc(T{ fval = s }) for str field: cgexpr
// leaves (AX=ptr, BX=len). Use CX for the heap
// base so BX=len survives both stores. Mirrors
// cmd/w6c/cgen.c:4184-4190.
emitline("\tMOVQ\t(SP), CX\n");
emitline("\tMOVQ\tAX, ");
emitint(fi.foff: i64);
emitline("(CX)\n");
emitline("\tMOVQ\tBX, ");
emitint((fi.foff + 8): i64);
emitline("(CX)\n");
fi = nil;
} else {
emitline("\tMOVQ\t(SP), BX\n");
let sop: str = fieldstoreop(c, fi);
@@ -15993,7 +16006,7 @@ fn cgalloc(c: *cgen, n: *node) void = {
emitint(fi.foff: i64);
emitline("(BX)\n");
fi = nil;
};
};};
} else {
fi = fi.finext;
};

View File

@@ -2775,6 +2775,19 @@ fn cgalloc(c: *cgen, n: *node) void = {
emitint(fi.foff: i64);
emitline("(BX)\n");
fi = nil;
} else { if (isstrtype(c, fi.tnode)) {
// alloc(T{ fval = s }) for str field: cgexpr
// leaves (AX=ptr, BX=len). Use CX for the heap
// base so BX=len survives both stores. Mirrors
// cmd/w6c/cgen.c:4184-4190.
emitline("\tMOVQ\t(SP), CX\n");
emitline("\tMOVQ\tAX, ");
emitint(fi.foff: i64);
emitline("(CX)\n");
emitline("\tMOVQ\tBX, ");
emitint((fi.foff + 8): i64);
emitline("(CX)\n");
fi = nil;
} else {
emitline("\tMOVQ\t(SP), BX\n");
let sop: str = fieldstoreop(c, fi);
@@ -2784,7 +2797,7 @@ fn cgalloc(c: *cgen, n: *node) void = {
emitint(fi.foff: i64);
emitline("(BX)\n");
fi = nil;
};
};};
} else {
fi = fi.finext;
};

View File

@@ -15984,6 +15984,19 @@ fn cgalloc(c: *cgen, n: *node) void = {
emitint(fi.foff: i64);
emitline("(BX)\n");
fi = nil;
} else { if (isstrtype(c, fi.tnode)) {
// alloc(T{ fval = s }) for str field: cgexpr
// leaves (AX=ptr, BX=len). Use CX for the heap
// base so BX=len survives both stores. Mirrors
// cmd/w6c/cgen.c:4184-4190.
emitline("\tMOVQ\t(SP), CX\n");
emitline("\tMOVQ\tAX, ");
emitint(fi.foff: i64);
emitline("(CX)\n");
emitline("\tMOVQ\tBX, ");
emitint((fi.foff + 8): i64);
emitline("(CX)\n");
fi = nil;
} else {
emitline("\tMOVQ\t(SP), BX\n");
let sop: str = fieldstoreop(c, fi);
@@ -15993,7 +16006,7 @@ fn cgalloc(c: *cgen, n: *node) void = {
emitint(fi.foff: i64);
emitline("(BX)\n");
fi = nil;
};
};};
} else {
fi = fi.finext;
};