selfhost+test: graduate wwstage sum-typed N_INDEX call-arg to tagged ABI (#12)
pushargsrev's widening detection was N_IDENT-only — N_INDEX of a sum-typed slice element fell through to the scalar widening branch, which hardcoded the param's first-variant tag (MOVQ $1, AX) and pushed AX as a single scalar word. Callees that match-dispatched on the runtime tag always ran the static-guess arm on garbage. cstage knew the arg's type via check.c so its widen[] flag stayed off and the natural-push tagged-arg arm pushed CX/DX/AX (high → low) high → low. wwstage now mirrors via two narrow arms in pushargsrev: the aistagged guard treats N_INDEX-of-sum-typed-element matching the param slot as already-tagged, and the natural-push fallthrough emits PUSHQ CX / DX / AX for the same shape. Both arms gate on istaggedtype(indexvaluetnode(arg)) so literal- and ident-source sum args stay on their existing paths. Sentinel 749_sumtype_forward table-drives the three forward shapes (N_INDEX, N_IDENT, literal) and asserts per-stage runtime plus a byte-id window over the callsite asm. Combined.ww regen for wwdump_ww and w6c_ww follows the cgen source change; smoke.combined.ww unaffected. Tests: 123/123 pass; bootstrap fixed point holds (ww2==ww3==ww4).
This commit is contained in:
@@ -7292,6 +7292,21 @@ fn pushargsrev(c: *cgen, arg: *node, param: *node) i32 = {
|
||||
if (taggedcallslot(c, arg) == slotsize(c, ptype)) {
|
||||
aistagged = true;
|
||||
};
|
||||
// #12: N_INDEX of a sum-typed slice element —
|
||||
// cgindex emits the same AX/DX/CX/R8 tagged ABI.
|
||||
// Without this gate the widening scalar branch
|
||||
// hardcodes the param's first-variant tag and
|
||||
// the callee reads a fixed arm on garbage.
|
||||
if (arg.kind == nkind.N_INDEX) {
|
||||
let etn: *node = indexvaluetnode(c, arg);
|
||||
if (etn != nil) {
|
||||
if (istaggedtype(c, etn)) {
|
||||
if (slotsize(c, etn) == slotsize(c, ptype)) {
|
||||
aistagged = true;
|
||||
};
|
||||
};
|
||||
};
|
||||
};
|
||||
if (!aistagged) {
|
||||
widensz = slotsize(c, ptype);
|
||||
let tagged: *node = resolvetagged(c, ptype);
|
||||
@@ -7591,6 +7606,22 @@ fn pushargsrev(c: *cgen, arg: *node, param: *node) i32 = {
|
||||
emitline("\tPUSHQ\tAX\n");
|
||||
return rest + tcs / 8;
|
||||
};
|
||||
// #12: N_INDEX of a sum-typed slice element. cgindex above left
|
||||
// the tagged-CALL ABI in AX/DX/CX/R8; the bare PUSHQ AX below
|
||||
// would only carry the tag word and drop the payload.
|
||||
if (arg.kind == nkind.N_INDEX) {
|
||||
let etn: *node = indexvaluetnode(c, arg);
|
||||
if (etn != nil) {
|
||||
if (istaggedtype(c, etn)) {
|
||||
let isz: i32 = slotsize(c, etn);
|
||||
if (isz > 24) { emitline("\tPUSHQ\tR8\n"); };
|
||||
if (isz > 16) { emitline("\tPUSHQ\tCX\n"); };
|
||||
if (isz > 8) { emitline("\tPUSHQ\tDX\n"); };
|
||||
emitline("\tPUSHQ\tAX\n");
|
||||
return rest + isz / 8;
|
||||
};
|
||||
};
|
||||
};
|
||||
emitline("\tPUSHQ\tAX\n");
|
||||
return rest + 1;
|
||||
};
|
||||
|
||||
@@ -152,6 +152,21 @@ fn pushargsrev(c: *cgen, arg: *node, param: *node) i32 = {
|
||||
if (taggedcallslot(c, arg) == slotsize(c, ptype)) {
|
||||
aistagged = true;
|
||||
};
|
||||
// #12: N_INDEX of a sum-typed slice element —
|
||||
// cgindex emits the same AX/DX/CX/R8 tagged ABI.
|
||||
// Without this gate the widening scalar branch
|
||||
// hardcodes the param's first-variant tag and
|
||||
// the callee reads a fixed arm on garbage.
|
||||
if (arg.kind == nkind.N_INDEX) {
|
||||
let etn: *node = indexvaluetnode(c, arg);
|
||||
if (etn != nil) {
|
||||
if (istaggedtype(c, etn)) {
|
||||
if (slotsize(c, etn) == slotsize(c, ptype)) {
|
||||
aistagged = true;
|
||||
};
|
||||
};
|
||||
};
|
||||
};
|
||||
if (!aistagged) {
|
||||
widensz = slotsize(c, ptype);
|
||||
let tagged: *node = resolvetagged(c, ptype);
|
||||
@@ -451,6 +466,22 @@ fn pushargsrev(c: *cgen, arg: *node, param: *node) i32 = {
|
||||
emitline("\tPUSHQ\tAX\n");
|
||||
return rest + tcs / 8;
|
||||
};
|
||||
// #12: N_INDEX of a sum-typed slice element. cgindex above left
|
||||
// the tagged-CALL ABI in AX/DX/CX/R8; the bare PUSHQ AX below
|
||||
// would only carry the tag word and drop the payload.
|
||||
if (arg.kind == nkind.N_INDEX) {
|
||||
let etn: *node = indexvaluetnode(c, arg);
|
||||
if (etn != nil) {
|
||||
if (istaggedtype(c, etn)) {
|
||||
let isz: i32 = slotsize(c, etn);
|
||||
if (isz > 24) { emitline("\tPUSHQ\tR8\n"); };
|
||||
if (isz > 16) { emitline("\tPUSHQ\tCX\n"); };
|
||||
if (isz > 8) { emitline("\tPUSHQ\tDX\n"); };
|
||||
emitline("\tPUSHQ\tAX\n");
|
||||
return rest + isz / 8;
|
||||
};
|
||||
};
|
||||
};
|
||||
emitline("\tPUSHQ\tAX\n");
|
||||
return rest + 1;
|
||||
};
|
||||
|
||||
@@ -7292,6 +7292,21 @@ fn pushargsrev(c: *cgen, arg: *node, param: *node) i32 = {
|
||||
if (taggedcallslot(c, arg) == slotsize(c, ptype)) {
|
||||
aistagged = true;
|
||||
};
|
||||
// #12: N_INDEX of a sum-typed slice element —
|
||||
// cgindex emits the same AX/DX/CX/R8 tagged ABI.
|
||||
// Without this gate the widening scalar branch
|
||||
// hardcodes the param's first-variant tag and
|
||||
// the callee reads a fixed arm on garbage.
|
||||
if (arg.kind == nkind.N_INDEX) {
|
||||
let etn: *node = indexvaluetnode(c, arg);
|
||||
if (etn != nil) {
|
||||
if (istaggedtype(c, etn)) {
|
||||
if (slotsize(c, etn) == slotsize(c, ptype)) {
|
||||
aistagged = true;
|
||||
};
|
||||
};
|
||||
};
|
||||
};
|
||||
if (!aistagged) {
|
||||
widensz = slotsize(c, ptype);
|
||||
let tagged: *node = resolvetagged(c, ptype);
|
||||
@@ -7591,6 +7606,22 @@ fn pushargsrev(c: *cgen, arg: *node, param: *node) i32 = {
|
||||
emitline("\tPUSHQ\tAX\n");
|
||||
return rest + tcs / 8;
|
||||
};
|
||||
// #12: N_INDEX of a sum-typed slice element. cgindex above left
|
||||
// the tagged-CALL ABI in AX/DX/CX/R8; the bare PUSHQ AX below
|
||||
// would only carry the tag word and drop the payload.
|
||||
if (arg.kind == nkind.N_INDEX) {
|
||||
let etn: *node = indexvaluetnode(c, arg);
|
||||
if (etn != nil) {
|
||||
if (istaggedtype(c, etn)) {
|
||||
let isz: i32 = slotsize(c, etn);
|
||||
if (isz > 24) { emitline("\tPUSHQ\tR8\n"); };
|
||||
if (isz > 16) { emitline("\tPUSHQ\tCX\n"); };
|
||||
if (isz > 8) { emitline("\tPUSHQ\tDX\n"); };
|
||||
emitline("\tPUSHQ\tAX\n");
|
||||
return rest + isz / 8;
|
||||
};
|
||||
};
|
||||
};
|
||||
emitline("\tPUSHQ\tAX\n");
|
||||
return rest + 1;
|
||||
};
|
||||
|
||||
Reference in New Issue
Block a user