w6c: materialize full tagged slot on N_IDENT-source return (#263) — cstage align-up to wwstage
cgreturn's passthrough predicate was TYPE-only (istagged && type-eq), with
no source-kind filter. It forwarded the source's AX/DX/CX unchanged, which
is correct ONLY when the source already materialized the full tagged slot
into registers — N_CALL / N_INDEX / N_DOT (the #261-broadened set). For a
tagged LOCAL ident, cgexpr loads only word0 (the tag) into AX, never the
payload into DX, so passthrough dropped the payload: `return v` of a
`(i32|void)=7i32` exited 0 instead of 7. wwstage was already correct — its
forwardtagged kind filter excludes N_IDENT, routing it through the
scratch-widen path. The runtime oracle (cstage 0, wwstage 7) proved cstage
is the bug; this aligns cstage UP.
Gate passthrough to {N_CALL,N_INDEX,N_DOT}; a tagged-ident return now falls
to the existing scratch-slot widen path (cg_widen_tagged_store tagged-subset
N_IDENT arm), byte-identical to wwstage's return scratch-widen. cstage-only
(no combined.ww regen — combined.ww embeds the unchanged wwstage source;
byte-id is blind here, the new 949 rows are the net).
test/949: tagged_ident_ret_i32 (7) + tagged_ident_ret_void (void tag
survives) + register-resident controls tagged_call_ret_ctrl /
tagged_dot_ret_ctrl (passthrough must still fire); INDEX control already
present. All dual-stage run + cs==ww byte-id.
This commit is contained in:
@@ -8843,7 +8843,21 @@ cgstmt(Cg *c, Node *n, Local **locals, int *frame)
|
||||
Type *vu = (vt && vt->kind == TY_NAMED)
|
||||
? vt->under : vt;
|
||||
int istagged = vu && vu->kind == TY_TAGGED;
|
||||
int passthrough = istagged && (vu == rt ||
|
||||
/* #263: passthrough forwards the source's AX/DX/CX
|
||||
* unchanged — correct ONLY when the source already
|
||||
* materialised the FULL tagged slot into registers:
|
||||
* N_CALL / N_INDEX / N_DOT (the #261-broadened set).
|
||||
* A tagged LOCAL ident leaves only word0 (the tag)
|
||||
* in AX (cgexpr of an ident loads a single word), so
|
||||
* DX (the payload) is garbage and the passthrough
|
||||
* drops it. Route a tagged-ident return through the
|
||||
* scratch-widen path below instead. Mirrors wwstage's
|
||||
* forwardtagged kind filter, which already excludes
|
||||
* N_IDENT (selfhost cgenstmt). */
|
||||
int srcreg = n->lhs->kind == N_CALL ||
|
||||
n->lhs->kind == N_INDEX ||
|
||||
n->lhs->kind == N_DOT;
|
||||
int passthrough = istagged && srcreg && (vu == rt ||
|
||||
type_eq(vt, cg_ret_type));
|
||||
int isstruct = vu && vu->kind == TY_STRUCT;
|
||||
/* #242: a tuple variant must be PACKED into the union
|
||||
|
||||
Reference in New Issue
Block a user