w6c: classify tagged call-result args by the stamped type
taggedcallslot gated on an N_IDENT callee + fnretlookup, so every N_DOT / wwi-decl'd cross-module callee (and every fn-pointer call) returned 0 and its tagged call-result ARG fell off the cursor-push path into a 16B scratch spill where cstage PUSHQes AX/DX (cstage keys the same push on args[i]->type, cgen.c tagged_arg_size). Read the stamped result type instead — the #209/#211 predicate-to-stamp discipline, same class as the fn-value cgident fix. Graduates BOTH remaining DATABYTEID_DIVERGED pins (r700_strings_byteindex frame 80->64, r839_xmod_nominal_match frame 32->16) — the ledger is EMPTY; the byteid gate ran 1389 data fixtures at 0 pinned-divergent. Lang rows cover the same-module control, fn-pointer, float-member, and str-member shapes (byte-identical each). Separate latent lead banked, NOT closed here: the tagged subset-widening call arg ((i64|bool) passed as (i64|bool|void)) byte-diverges pre-existing — cstage stages through a 16B local, wwstage passes direct; runtime-equivalent.
This commit is contained in:
11
Makefile
11
Makefile
@@ -730,16 +730,7 @@ DATABYTEID_EXPECTED_MIN = 915
|
||||
# discipline): each entry must still build on both stages AND still differ.
|
||||
# When a compiler fix lands the entry fails demanding graduation out of
|
||||
# this list rather than silently widening coverage.
|
||||
# r700_strings_byteindex: latent, exposed by the 700_e2e migration —
|
||||
# wwstage spills a wwi-decl'd tagged call-result arg through a 16B
|
||||
# scratch pair where cstage PUSHQes AX/DX (frame 64 vs 80); runtime-
|
||||
# equivalent, sibling of the closed #211 name-keyed family.
|
||||
# r839_xmod_nominal_match: latent, exposed by the 839 migration (the
|
||||
# carrier waived byte-id silently) — same spill family as r700: wwstage
|
||||
# routes the cross-module tagged call-result through a 16B scratch pair
|
||||
# where cstage PUSHQes AX/DX (frame 16 vs 32); runtime-equivalent
|
||||
# (both stages run exit 42).
|
||||
DATABYTEID_DIVERGED = r700_strings_byteindex r839_xmod_nominal_match
|
||||
DATABYTEID_DIVERGED =
|
||||
$(if $(DATABYTEID_FILES),,$(error test-byteid: empty data corpus))
|
||||
test-data-byteid: $(BIN)/ww $(BIN)/w6c $(BIN)/w6c_ww
|
||||
@work=$$(mktemp -d "$(CURDIR)/$(DATABYTEID_DIR).XXXXXX") || exit 1; \
|
||||
|
||||
@@ -1446,12 +1446,14 @@ fn pushargsrev(c: *cgen, arg: *syntax.node, param: *syntax.node, memphase: bool,
|
||||
export fn taggedcallslot(c: *cgen, n: *syntax.node) i32 = {
|
||||
if (n == nil) { return 0; };
|
||||
if (n.kind != syntax.nkind.N_CALL) { return 0; };
|
||||
let callee: *syntax.node = n.lhs;
|
||||
if (callee == nil) { return 0; };
|
||||
if (callee.kind != syntax.nkind.N_IDENT) { return 0; };
|
||||
let rtyp: *syntax.node = fnretlookup(c, callee.str);
|
||||
if (!istaggedtype(c, rtyp)) { return 0; };
|
||||
return slotsize(c, rtyp);
|
||||
// Stamped result type, never a callee-name lookup (#209/#211
|
||||
// discipline): the old N_IDENT + fnretlookup gate returned 0 for
|
||||
// every N_DOT / wwi-decl'd cross-module callee, so their tagged
|
||||
// call-result ARGS fell off the cursor-push path into a 16B
|
||||
// scratch spill. cstage keys the same push on args[i]->type
|
||||
// (cgen.c tagged_arg_size).
|
||||
if (!istaggedtype(c, n)) { return 0; };
|
||||
return slotsize(c, n);
|
||||
};
|
||||
|
||||
fn nodeisslice(c: *cgen, n: *syntax.node) bool = {
|
||||
|
||||
49
test/lang/taggedarg_callresult_test.ww
Normal file
49
test/lang/taggedarg_callresult_test.ww
Normal file
@@ -0,0 +1,49 @@
|
||||
// taggedarg_callresult_test — a tagged-union call RESULT passed
|
||||
// directly as a call ARGUMENT rides the register cursor (PUSHQ AX/DX
|
||||
// pairs), classified by the STAMPED result type (taggedcallslot); the
|
||||
// old callee-name gate dropped fn-pointer and cross-module callees to
|
||||
// a 16B scratch spill (the r700_strings_byteindex / r839 byteid pins;
|
||||
// the corpus fixtures own the cross-module byte-id legs).
|
||||
|
||||
package taggedarg_callresult_test;
|
||||
|
||||
fn ok(v: i64) (i64 | void) = { return v; };
|
||||
fn unwrap(r: (i64 | void)) i64 = {
|
||||
match (r) {
|
||||
case let n: i64 => return n;
|
||||
case void => return -1;
|
||||
};
|
||||
};
|
||||
|
||||
@test fn samemod() void = {
|
||||
assert(unwrap(ok(42)) == 42i64);
|
||||
};
|
||||
|
||||
@test fn fnptr() void = {
|
||||
let f: *fn(v: i64) (i64 | void) = &ok;
|
||||
assert(unwrap(f(7)) == 7i64);
|
||||
};
|
||||
|
||||
fn mkf(v: f64) (f64 | void) = { return v; };
|
||||
fn pickf(r: (f64 | void)) i32 = {
|
||||
match (r) {
|
||||
case let d: f64 => return (d: i32);
|
||||
case void => return -1;
|
||||
};
|
||||
};
|
||||
|
||||
@test fn floatmember() void = {
|
||||
assert(pickf(mkf(5.0)) == 5);
|
||||
};
|
||||
|
||||
fn mks(s: str) (str | void) = { return s; };
|
||||
fn picks(r: (str | void)) i32 = {
|
||||
match (r) {
|
||||
case let s: str => return (s.len: i32);
|
||||
case void => return -1;
|
||||
};
|
||||
};
|
||||
|
||||
@test fn strmember() void = {
|
||||
assert(picks(mks("hello")) == 5);
|
||||
};
|
||||
Reference in New Issue
Block a user